* Moved the vm_page initialization from vm_page.cpp:vm_page_init() to the new
vm_page::Init().
* Made vm_page::wired_count private and added accessor methods.
* Added VMCache::fWiredPagesCount (the number of wired pages the cache
contains) and accessor methods.
* Made more use of vm_page::IsMapped().
* vm_copy_on_write_area(): Added vm_page_reservation* parameter that can be
used to request a special handling for wired pages. If given the wired pages
are replaced by copies and the original pages are moved to the upper cache.
* vm_copy_area():
- We don't need to do any wired ranges handling, if the source area is a
B_SHARED_AREA, since we don't touch the area's mappings in this case.
- We no longer wait for wired ranges of the concerned areas to disappear.
Instead we use the new vm_copy_on_write_area() feature and just let it
copy the wired pages. This fixes #6288, an issue introduced with the use
of user mutexes in libroot: When executing multiple concurrent fork()s all
but the first one would wait on the fork mutex, which (being a user mutex)
would wire a page that the vm_copy_area() of the first fork() would wait
for.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37460 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -101,6 +101,10 @@ public:
|
|||||||
void MovePage(vm_page* page);
|
void MovePage(vm_page* page);
|
||||||
void MoveAllPages(VMCache* fromCache);
|
void MoveAllPages(VMCache* fromCache);
|
||||||
|
|
||||||
|
inline page_num_t WiredPagesCount() const;
|
||||||
|
inline void IncrementWiredPagesCount();
|
||||||
|
inline void DecrementWiredPagesCount();
|
||||||
|
|
||||||
void AddConsumer(VMCache* consumer);
|
void AddConsumer(VMCache* consumer);
|
||||||
|
|
||||||
status_t InsertAreaLocked(VMArea* area);
|
status_t InsertAreaLocked(VMArea* area);
|
||||||
@@ -197,6 +201,7 @@ private:
|
|||||||
PageEventWaiter* fPageEventWaiters;
|
PageEventWaiter* fPageEventWaiters;
|
||||||
void* fUserData;
|
void* fUserData;
|
||||||
VMCacheRef* fCacheRef;
|
VMCacheRef* fCacheRef;
|
||||||
|
page_num_t fWiredPagesCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -308,6 +313,49 @@ VMCache::MarkPageUnbusy(vm_page* page)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
page_num_t
|
||||||
|
VMCache::WiredPagesCount() const
|
||||||
|
{
|
||||||
|
return fWiredPagesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VMCache::IncrementWiredPagesCount()
|
||||||
|
{
|
||||||
|
ASSERT(fWiredPagesCount < page_count);
|
||||||
|
|
||||||
|
fWiredPagesCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VMCache::DecrementWiredPagesCount()
|
||||||
|
{
|
||||||
|
ASSERT(fWiredPagesCount > 0);
|
||||||
|
|
||||||
|
fWiredPagesCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// vm_page methods implemented here to avoid VMCache.h inclusion in vm_types.h
|
||||||
|
|
||||||
|
inline void
|
||||||
|
vm_page::IncrementWiredCount()
|
||||||
|
{
|
||||||
|
if (fWiredCount++ == 0)
|
||||||
|
cache_ref->cache->IncrementWiredPagesCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
vm_page::DecrementWiredCount()
|
||||||
|
{
|
||||||
|
if (--fWiredCount == 0)
|
||||||
|
cache_ref->cache->DecrementWiredPagesCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#define _KERNEL_VM_VM_TYPES_H
|
#define _KERNEL_VM_VM_TYPES_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
#include <arch/vm_types.h>
|
#include <arch/vm_types.h>
|
||||||
#include <condition_variable.h>
|
#include <condition_variable.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
@@ -142,7 +144,8 @@ public:
|
|||||||
uint8 unused : 1;
|
uint8 unused : 1;
|
||||||
|
|
||||||
uint8 usage_count;
|
uint8 usage_count;
|
||||||
uint16 wired_count;
|
|
||||||
|
inline void Init(page_num_t pageNumber);
|
||||||
|
|
||||||
VMCacheRef* CacheRef() const { return cache_ref; }
|
VMCacheRef* CacheRef() const { return cache_ref; }
|
||||||
void SetCacheRef(VMCacheRef* cacheRef) { this->cache_ref = cacheRef; }
|
void SetCacheRef(VMCacheRef* cacheRef) { this->cache_ref = cacheRef; }
|
||||||
@@ -151,11 +154,19 @@ public:
|
|||||||
{ return cache_ref != NULL ? cache_ref->cache : NULL; }
|
{ return cache_ref != NULL ? cache_ref->cache : NULL; }
|
||||||
|
|
||||||
bool IsMapped() const
|
bool IsMapped() const
|
||||||
{ return wired_count > 0 || !mappings.IsEmpty(); }
|
{ return fWiredCount > 0 || !mappings.IsEmpty(); }
|
||||||
|
|
||||||
uint8 State() const { return state; }
|
uint8 State() const { return state; }
|
||||||
void InitState(uint8 newState);
|
void InitState(uint8 newState);
|
||||||
void SetState(uint8 newState);
|
void SetState(uint8 newState);
|
||||||
|
|
||||||
|
inline uint16 WiredCount() const { return fWiredCount; }
|
||||||
|
inline void IncrementWiredCount();
|
||||||
|
inline void DecrementWiredCount();
|
||||||
|
// both implemented in VMCache.h to avoid inclusion here
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16 fWiredCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -180,6 +191,25 @@ enum {
|
|||||||
#define VM_PAGE_ALLOC_BUSY 0x00000020
|
#define VM_PAGE_ALLOC_BUSY 0x00000020
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
vm_page::Init(page_num_t pageNumber)
|
||||||
|
{
|
||||||
|
physical_page_number = pageNumber;
|
||||||
|
InitState(PAGE_STATE_FREE);
|
||||||
|
new(&mappings) vm_page_mappings();
|
||||||
|
fWiredCount = 0;
|
||||||
|
usage_count = 0;
|
||||||
|
busy_writing = false;
|
||||||
|
SetCacheRef(NULL);
|
||||||
|
#if DEBUG_PAGE_QUEUE
|
||||||
|
queue = NULL;
|
||||||
|
#endif
|
||||||
|
#if DEBUG_PAGE_ACCESS
|
||||||
|
accessing_thread = -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG_PAGE_ACCESS
|
#if DEBUG_PAGE_ACCESS
|
||||||
# include <thread.h>
|
# include <thread.h>
|
||||||
|
|
||||||
|
|||||||
@@ -409,9 +409,9 @@ X86VMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
page->mappings.Remove(mapping);
|
page->mappings.Remove(mapping);
|
||||||
queue.Add(mapping);
|
queue.Add(mapping);
|
||||||
} else
|
} else
|
||||||
page->wired_count--;
|
page->DecrementWiredCount();
|
||||||
|
|
||||||
if (page->wired_count == 0 && page->mappings.IsEmpty()) {
|
if (!page->IsMapped()) {
|
||||||
atomic_add(&gMappedPagesCount, -1);
|
atomic_add(&gMappedPagesCount, -1);
|
||||||
|
|
||||||
if (updatePageQueue) {
|
if (updatePageQueue) {
|
||||||
@@ -475,7 +475,7 @@ X86VMTranslationMap32Bit::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
|||||||
VMCache* cache = page->Cache();
|
VMCache* cache = page->Cache();
|
||||||
|
|
||||||
bool pageFullyUnmapped = false;
|
bool pageFullyUnmapped = false;
|
||||||
if (page->wired_count == 0 && page->mappings.IsEmpty()) {
|
if (!page->IsMapped()) {
|
||||||
atomic_add(&gMappedPagesCount, -1);
|
atomic_add(&gMappedPagesCount, -1);
|
||||||
pageFullyUnmapped = true;
|
pageFullyUnmapped = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -451,9 +451,9 @@ X86VMTranslationMapPAE::UnmapPages(VMArea* area, addr_t base, size_t size,
|
|||||||
page->mappings.Remove(mapping);
|
page->mappings.Remove(mapping);
|
||||||
queue.Add(mapping);
|
queue.Add(mapping);
|
||||||
} else
|
} else
|
||||||
page->wired_count--;
|
page->DecrementWiredCount();
|
||||||
|
|
||||||
if (page->wired_count == 0 && page->mappings.IsEmpty()) {
|
if (!page->IsMapped()) {
|
||||||
atomic_add(&gMappedPagesCount, -1);
|
atomic_add(&gMappedPagesCount, -1);
|
||||||
|
|
||||||
if (updatePageQueue) {
|
if (updatePageQueue) {
|
||||||
@@ -515,7 +515,7 @@ X86VMTranslationMapPAE::UnmapArea(VMArea* area, bool deletingAddressSpace,
|
|||||||
VMCache* cache = page->Cache();
|
VMCache* cache = page->Cache();
|
||||||
|
|
||||||
bool pageFullyUnmapped = false;
|
bool pageFullyUnmapped = false;
|
||||||
if (page->wired_count == 0 && page->mappings.IsEmpty()) {
|
if (!page->IsMapped()) {
|
||||||
atomic_add(&gMappedPagesCount, -1);
|
atomic_add(&gMappedPagesCount, -1);
|
||||||
pageFullyUnmapped = true;
|
pageFullyUnmapped = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1382,7 +1382,7 @@ MemoryManager::_MapChunk(VMArea* vmArea, addr_t address, size_t size,
|
|||||||
vm_page* page = vm_page_allocate_page(&reservation, PAGE_STATE_WIRED);
|
vm_page* page = vm_page_allocate_page(&reservation, PAGE_STATE_WIRED);
|
||||||
cache->InsertPage(page, offset);
|
cache->InsertPage(page, offset);
|
||||||
|
|
||||||
page->wired_count++;
|
page->IncrementWiredCount();
|
||||||
atomic_add(&gMappedPagesCount, 1);
|
atomic_add(&gMappedPagesCount, 1);
|
||||||
DEBUG_PAGE_ACCESS_END(page);
|
DEBUG_PAGE_ACCESS_END(page);
|
||||||
|
|
||||||
@@ -1435,7 +1435,7 @@ MemoryManager::_UnmapChunk(VMArea* vmArea, addr_t address, size_t size,
|
|||||||
|
|
||||||
DEBUG_PAGE_ACCESS_START(page);
|
DEBUG_PAGE_ACCESS_START(page);
|
||||||
|
|
||||||
page->wired_count--;
|
page->DecrementWiredCount();
|
||||||
|
|
||||||
cache->RemovePage(page);
|
cache->RemovePage(page);
|
||||||
// the iterator is remove-safe
|
// the iterator is remove-safe
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ PageCacheLocker::_IgnorePage(vm_page* page)
|
|||||||
{
|
{
|
||||||
if (page->busy || page->State() == PAGE_STATE_WIRED
|
if (page->busy || page->State() == PAGE_STATE_WIRED
|
||||||
|| page->State() == PAGE_STATE_FREE || page->State() == PAGE_STATE_CLEAR
|
|| page->State() == PAGE_STATE_FREE || page->State() == PAGE_STATE_CLEAR
|
||||||
|| page->State() == PAGE_STATE_UNUSED || page->wired_count > 0)
|
|| page->State() == PAGE_STATE_UNUSED || page->WiredCount() > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -594,6 +594,7 @@ VMCache::Init(uint32 cacheType, uint32 allocationFlags)
|
|||||||
committed_size = 0;
|
committed_size = 0;
|
||||||
temporary = 0;
|
temporary = 0;
|
||||||
page_count = 0;
|
page_count = 0;
|
||||||
|
fWiredPagesCount = 0;
|
||||||
type = cacheType;
|
type = cacheType;
|
||||||
fPageEventWaiters = NULL;
|
fPageEventWaiters = NULL;
|
||||||
|
|
||||||
@@ -634,7 +635,7 @@ VMCache::Delete()
|
|||||||
|
|
||||||
// free all of the pages in the cache
|
// free all of the pages in the cache
|
||||||
while (vm_page* page = pages.Root()) {
|
while (vm_page* page = pages.Root()) {
|
||||||
if (!page->mappings.IsEmpty() || page->wired_count != 0) {
|
if (!page->mappings.IsEmpty() || page->WiredCount() != 0) {
|
||||||
panic("remove page %p from cache %p: page still has mappings!\n",
|
panic("remove page %p from cache %p: page still has mappings!\n",
|
||||||
page, this);
|
page, this);
|
||||||
}
|
}
|
||||||
@@ -758,6 +759,9 @@ VMCache::InsertPage(vm_page* page, off_t offset)
|
|||||||
#endif // KDEBUG
|
#endif // KDEBUG
|
||||||
|
|
||||||
pages.Insert(page);
|
pages.Insert(page);
|
||||||
|
|
||||||
|
if (page->WiredCount() > 0)
|
||||||
|
IncrementWiredPagesCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -781,6 +785,9 @@ VMCache::RemovePage(vm_page* page)
|
|||||||
pages.Remove(page);
|
pages.Remove(page);
|
||||||
page_count--;
|
page_count--;
|
||||||
page->SetCacheRef(NULL);
|
page->SetCacheRef(NULL);
|
||||||
|
|
||||||
|
if (page->WiredCount() > 0)
|
||||||
|
DecrementWiredPagesCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -804,6 +811,12 @@ VMCache::MovePage(vm_page* page)
|
|||||||
pages.Insert(page);
|
pages.Insert(page);
|
||||||
page_count++;
|
page_count++;
|
||||||
page->SetCacheRef(fCacheRef);
|
page->SetCacheRef(fCacheRef);
|
||||||
|
|
||||||
|
if (page->WiredCount() > 0) {
|
||||||
|
IncrementWiredPagesCount();
|
||||||
|
oldCache->DecrementWiredPagesCount();
|
||||||
|
}
|
||||||
|
|
||||||
T2(InsertPage(this, page, page->cache_offset << PAGE_SHIFT));
|
T2(InsertPage(this, page, page->cache_offset << PAGE_SHIFT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -821,6 +834,8 @@ VMCache::MoveAllPages(VMCache* fromCache)
|
|||||||
std::swap(fromCache->pages, pages);
|
std::swap(fromCache->pages, pages);
|
||||||
page_count = fromCache->page_count;
|
page_count = fromCache->page_count;
|
||||||
fromCache->page_count = 0;
|
fromCache->page_count = 0;
|
||||||
|
fWiredPagesCount = fromCache->fWiredPagesCount;
|
||||||
|
fromCache->fWiredPagesCount = 0;
|
||||||
|
|
||||||
// swap the VMCacheRefs
|
// swap the VMCacheRefs
|
||||||
mutex_lock(&sCacheListLock);
|
mutex_lock(&sCacheListLock);
|
||||||
@@ -1077,7 +1092,7 @@ VMCache::Resize(off_t newSize, int priority)
|
|||||||
// remove the page and put it into the free queue
|
// remove the page and put it into the free queue
|
||||||
DEBUG_PAGE_ACCESS_START(page);
|
DEBUG_PAGE_ACCESS_START(page);
|
||||||
vm_remove_all_page_mappings(page);
|
vm_remove_all_page_mappings(page);
|
||||||
ASSERT(page->wired_count == 0);
|
ASSERT(page->WiredCount() == 0);
|
||||||
// TODO: Find a real solution! If the page is wired
|
// TODO: Find a real solution! If the page is wired
|
||||||
// temporarily (e.g. by lock_memory()), we actually must not
|
// temporarily (e.g. by lock_memory()), we actually must not
|
||||||
// unmap it!
|
// unmap it!
|
||||||
@@ -1123,7 +1138,7 @@ VMCache::FlushAndRemoveAllPages()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// We can't remove mapped pages.
|
// We can't remove mapped pages.
|
||||||
if (page->wired_count > 0 || !page->mappings.IsEmpty())
|
if (page->IsMapped())
|
||||||
return B_BUSY;
|
return B_BUSY;
|
||||||
|
|
||||||
DEBUG_PAGE_ACCESS_START(page);
|
DEBUG_PAGE_ACCESS_START(page);
|
||||||
@@ -1311,7 +1326,7 @@ VMCache::Dump(bool showPages) const
|
|||||||
" state %u (%s) wired_count %u\n", page,
|
" state %u (%s) wired_count %u\n", page,
|
||||||
page->physical_page_number, page->cache_offset,
|
page->physical_page_number, page->cache_offset,
|
||||||
page->State(), page_state_to_string(page->State()),
|
page->State(), page_state_to_string(page->State()),
|
||||||
page->wired_count);
|
page->WiredCount());
|
||||||
} else {
|
} else {
|
||||||
kprintf("\t%p DUMMY PAGE state %u (%s)\n",
|
kprintf("\t%p DUMMY PAGE state %u (%s)\n",
|
||||||
page, page->State(), page_state_to_string(page->State()));
|
page, page->State(), page_state_to_string(page->State()));
|
||||||
|
|||||||
@@ -146,11 +146,11 @@ VMTranslationMap::PageUnmapped(VMArea* area, page_num_t pageNumber,
|
|||||||
B_PRIxPHYSADDR ", accessed: %d, modified: %d", page,
|
B_PRIxPHYSADDR ", accessed: %d, modified: %d", page,
|
||||||
pageNumber, accessed, modified);
|
pageNumber, accessed, modified);
|
||||||
} else
|
} else
|
||||||
page->wired_count--;
|
page->DecrementWiredCount();
|
||||||
|
|
||||||
recursive_lock_unlock(&fLock);
|
recursive_lock_unlock(&fLock);
|
||||||
|
|
||||||
if (page->wired_count == 0 && page->mappings.IsEmpty()) {
|
if (!page->IsMapped()) {
|
||||||
atomic_add(&gMappedPagesCount, -1);
|
atomic_add(&gMappedPagesCount, -1);
|
||||||
|
|
||||||
if (updatePageQueue) {
|
if (updatePageQueue) {
|
||||||
@@ -203,11 +203,11 @@ VMTranslationMap::UnaccessedPageUnmapped(VMArea* area, page_num_t pageNumber)
|
|||||||
ASSERT_PRINT(mapping != NULL, "page: %p, page number: %#"
|
ASSERT_PRINT(mapping != NULL, "page: %p, page number: %#"
|
||||||
B_PRIxPHYSADDR, page, pageNumber);
|
B_PRIxPHYSADDR, page, pageNumber);
|
||||||
} else
|
} else
|
||||||
page->wired_count--;
|
page->DecrementWiredCount();
|
||||||
|
|
||||||
recursive_lock_unlock(&fLock);
|
recursive_lock_unlock(&fLock);
|
||||||
|
|
||||||
if (page->wired_count == 0 && page->mappings.IsEmpty())
|
if (!page->IsMapped())
|
||||||
atomic_add(&gMappedPagesCount, -1);
|
atomic_add(&gMappedPagesCount, -1);
|
||||||
|
|
||||||
if (mapping != NULL) {
|
if (mapping != NULL) {
|
||||||
|
|||||||
+121
-36
@@ -406,8 +406,9 @@ private:
|
|||||||
static inline void
|
static inline void
|
||||||
increment_page_wired_count(vm_page* page)
|
increment_page_wired_count(vm_page* page)
|
||||||
{
|
{
|
||||||
if (page->wired_count++ == 0 && page->mappings.IsEmpty())
|
if (!page->IsMapped())
|
||||||
atomic_add(&gMappedPagesCount, 1);
|
atomic_add(&gMappedPagesCount, 1);
|
||||||
|
page->IncrementWiredCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -416,7 +417,8 @@ increment_page_wired_count(vm_page* page)
|
|||||||
static inline void
|
static inline void
|
||||||
decrement_page_wired_count(vm_page* page)
|
decrement_page_wired_count(vm_page* page)
|
||||||
{
|
{
|
||||||
if (--page->wired_count == 0 && page->mappings.IsEmpty())
|
page->DecrementWiredCount();
|
||||||
|
if (!page->IsMapped())
|
||||||
atomic_add(&gMappedPagesCount, -1);
|
atomic_add(&gMappedPagesCount, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +488,7 @@ map_page(VMArea* area, vm_page* page, addr_t address, uint32 protection,
|
|||||||
{
|
{
|
||||||
VMTranslationMap* map = area->address_space->TranslationMap();
|
VMTranslationMap* map = area->address_space->TranslationMap();
|
||||||
|
|
||||||
bool wasMapped = page->wired_count > 0 || !page->mappings.IsEmpty();
|
bool wasMapped = page->IsMapped();
|
||||||
|
|
||||||
if (area->wiring == B_NO_LOCK) {
|
if (area->wiring == B_NO_LOCK) {
|
||||||
DEBUG_PAGE_ACCESS_CHECK(page);
|
DEBUG_PAGE_ACCESS_CHECK(page);
|
||||||
@@ -508,7 +510,7 @@ map_page(VMArea* area, vm_page* page, addr_t address, uint32 protection,
|
|||||||
area->MemoryType(), reservation);
|
area->MemoryType(), reservation);
|
||||||
|
|
||||||
// insert mapping into lists
|
// insert mapping into lists
|
||||||
if (page->mappings.IsEmpty() && page->wired_count == 0)
|
if (!page->IsMapped())
|
||||||
atomic_add(&gMappedPagesCount, 1);
|
atomic_add(&gMappedPagesCount, 1);
|
||||||
|
|
||||||
page->mappings.Add(mapping);
|
page->mappings.Add(mapping);
|
||||||
@@ -1341,8 +1343,8 @@ vm_create_anonymous_area(team_id team, const char *name, addr_t size,
|
|||||||
|
|
||||||
DEBUG_PAGE_ACCESS_START(page);
|
DEBUG_PAGE_ACCESS_START(page);
|
||||||
|
|
||||||
increment_page_wired_count(page);
|
|
||||||
cache->InsertPage(page, offset);
|
cache->InsertPage(page, offset);
|
||||||
|
increment_page_wired_count(page);
|
||||||
vm_page_set_state(page, PAGE_STATE_WIRED);
|
vm_page_set_state(page, PAGE_STATE_WIRED);
|
||||||
page->busy = false;
|
page->busy = false;
|
||||||
|
|
||||||
@@ -1377,8 +1379,8 @@ vm_create_anonymous_area(team_id team, const char *name, addr_t size,
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
panic("couldn't map physical page in page run\n");
|
panic("couldn't map physical page in page run\n");
|
||||||
|
|
||||||
increment_page_wired_count(page);
|
|
||||||
cache->InsertPage(page, offset);
|
cache->InsertPage(page, offset);
|
||||||
|
increment_page_wired_count(page);
|
||||||
|
|
||||||
DEBUG_PAGE_ACCESS_END(page);
|
DEBUG_PAGE_ACCESS_END(page);
|
||||||
}
|
}
|
||||||
@@ -2152,14 +2154,22 @@ vm_delete_area(team_id team, area_id id, bool kernel)
|
|||||||
|
|
||||||
/*! Creates a new cache on top of given cache, moves all areas from
|
/*! Creates a new cache on top of given cache, moves all areas from
|
||||||
the old cache to the new one, and changes the protection of all affected
|
the old cache to the new one, and changes the protection of all affected
|
||||||
areas' pages to read-only.
|
areas' pages to read-only. If requested, wired pages are moved up to the
|
||||||
|
new cache and copies are added to the old cache in their place.
|
||||||
Preconditions:
|
Preconditions:
|
||||||
- The given cache must be locked.
|
- The given cache must be locked.
|
||||||
- All of the cache's areas' address spaces must be read locked.
|
- All of the cache's areas' address spaces must be read locked.
|
||||||
- None of the cache's areas must have any wired ranges.
|
- Either the cache must not have any wired ranges or a page reservation for
|
||||||
|
all wired pages must be provided, so they can be copied.
|
||||||
|
|
||||||
|
\param lowerCache The cache on top of which a new cache shall be created.
|
||||||
|
\param wiredPagesReservation If \c NULL there must not be any wired pages
|
||||||
|
in \a lowerCache. Otherwise as many pages must be reserved as the cache
|
||||||
|
has wired page. The wired pages are copied in this case.
|
||||||
*/
|
*/
|
||||||
static status_t
|
static status_t
|
||||||
vm_copy_on_write_area(VMCache* lowerCache)
|
vm_copy_on_write_area(VMCache* lowerCache,
|
||||||
|
vm_page_reservation* wiredPagesReservation)
|
||||||
{
|
{
|
||||||
VMCache* upperCache;
|
VMCache* upperCache;
|
||||||
|
|
||||||
@@ -2187,20 +2197,64 @@ vm_copy_on_write_area(VMCache* lowerCache)
|
|||||||
|
|
||||||
lowerCache->AddConsumer(upperCache);
|
lowerCache->AddConsumer(upperCache);
|
||||||
|
|
||||||
// We now need to remap all pages from all of the cache's areas read-only, so
|
// We now need to remap all pages from all of the cache's areas read-only,
|
||||||
// that a copy will be created on next write access
|
// so that a copy will be created on next write access. If there are wired
|
||||||
|
// pages, we keep their protection, move them to the upper cache and create
|
||||||
|
// copies for the lower cache.
|
||||||
|
if (wiredPagesReservation != NULL) {
|
||||||
|
// We need to handle wired pages -- iterate through the cache's pages.
|
||||||
|
for (VMCachePagesTree::Iterator it = lowerCache->pages.GetIterator();
|
||||||
|
vm_page* page = it.Next();) {
|
||||||
|
if (page->WiredCount() > 0) {
|
||||||
|
// allocate a new page and copy the wired one
|
||||||
|
vm_page* copiedPage = vm_page_allocate_page(
|
||||||
|
wiredPagesReservation, PAGE_STATE_ACTIVE);
|
||||||
|
|
||||||
for (VMArea* tempArea = upperCache->areas; tempArea != NULL;
|
vm_memcpy_physical_page(
|
||||||
tempArea = tempArea->cache_next) {
|
copiedPage->physical_page_number * B_PAGE_SIZE,
|
||||||
// The area must be readable in the same way it was previously writable
|
page->physical_page_number * B_PAGE_SIZE);
|
||||||
uint32 protection = B_KERNEL_READ_AREA;
|
|
||||||
if ((tempArea->protection & B_READ_AREA) != 0)
|
|
||||||
protection |= B_READ_AREA;
|
|
||||||
|
|
||||||
VMTranslationMap* map = tempArea->address_space->TranslationMap();
|
// move the wired page to the upper cache (note: removing is OK
|
||||||
map->Lock();
|
// with the SplayTree iterator) and insert the copy
|
||||||
map->ProtectArea(tempArea, protection);
|
upperCache->MovePage(page);
|
||||||
map->Unlock();
|
lowerCache->InsertPage(copiedPage,
|
||||||
|
page->cache_offset * B_PAGE_SIZE);
|
||||||
|
|
||||||
|
DEBUG_PAGE_ACCESS_END(copiedPage);
|
||||||
|
} else {
|
||||||
|
// Change the protection of this page in all areas.
|
||||||
|
for (VMArea* tempArea = upperCache->areas; tempArea != NULL;
|
||||||
|
tempArea = tempArea->cache_next) {
|
||||||
|
// The area must be readable in the same way it was
|
||||||
|
// previously writable.
|
||||||
|
uint32 protection = B_KERNEL_READ_AREA;
|
||||||
|
if ((tempArea->protection & B_READ_AREA) != 0)
|
||||||
|
protection |= B_READ_AREA;
|
||||||
|
|
||||||
|
VMTranslationMap* map
|
||||||
|
= tempArea->address_space->TranslationMap();
|
||||||
|
map->Lock();
|
||||||
|
map->ProtectPage(tempArea,
|
||||||
|
virtual_page_address(tempArea, page), protection);
|
||||||
|
map->Unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// just change the protection of all areas
|
||||||
|
for (VMArea* tempArea = upperCache->areas; tempArea != NULL;
|
||||||
|
tempArea = tempArea->cache_next) {
|
||||||
|
// The area must be readable in the same way it was previously
|
||||||
|
// writable.
|
||||||
|
uint32 protection = B_KERNEL_READ_AREA;
|
||||||
|
if ((tempArea->protection & B_READ_AREA) != 0)
|
||||||
|
protection |= B_READ_AREA;
|
||||||
|
|
||||||
|
VMTranslationMap* map = tempArea->address_space->TranslationMap();
|
||||||
|
map->Lock();
|
||||||
|
map->ProtectArea(tempArea, protection);
|
||||||
|
map->Unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vm_area_put_locked_cache(upperCache);
|
vm_area_put_locked_cache(upperCache);
|
||||||
@@ -2232,6 +2286,9 @@ vm_copy_area(team_id team, const char* name, void** _address,
|
|||||||
status_t status;
|
status_t status;
|
||||||
bool sharedArea;
|
bool sharedArea;
|
||||||
|
|
||||||
|
page_num_t wiredPages = 0;
|
||||||
|
vm_page_reservation wiredPagesReservation;
|
||||||
|
|
||||||
bool restart;
|
bool restart;
|
||||||
do {
|
do {
|
||||||
restart = false;
|
restart = false;
|
||||||
@@ -2249,22 +2306,48 @@ vm_copy_area(team_id team, const char* name, void** _address,
|
|||||||
|
|
||||||
sharedArea = (source->protection & B_SHARED_AREA) != 0;
|
sharedArea = (source->protection & B_SHARED_AREA) != 0;
|
||||||
|
|
||||||
// Make sure the source area (respectively, if not shared, all areas of
|
page_num_t oldWiredPages = wiredPages;
|
||||||
// the cache) doesn't have any wired ranges.
|
wiredPages = 0;
|
||||||
if (sharedArea) {
|
|
||||||
if (wait_if_area_is_wired(source, &locker, &cacheLocker))
|
// If the source area isn't shared, count the number of wired pages in
|
||||||
|
// the cache and reserve as many pages.
|
||||||
|
if (!sharedArea) {
|
||||||
|
wiredPages = cache->WiredPagesCount();
|
||||||
|
|
||||||
|
if (wiredPages > oldWiredPages) {
|
||||||
|
cacheLocker.Unlock();
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
if (oldWiredPages > 0)
|
||||||
|
vm_page_unreserve_pages(&wiredPagesReservation);
|
||||||
|
|
||||||
|
vm_page_reserve_pages(&wiredPagesReservation, wiredPages,
|
||||||
|
VM_PRIORITY_USER);
|
||||||
|
|
||||||
restart = true;
|
restart = true;
|
||||||
} else {
|
|
||||||
for (VMArea* area = cache->areas; area != NULL;
|
|
||||||
area = area->cache_next) {
|
|
||||||
if (wait_if_area_is_wired(area, &locker, &cacheLocker)) {
|
|
||||||
restart = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
} else if (oldWiredPages > 0)
|
||||||
|
vm_page_unreserve_pages(&wiredPagesReservation);
|
||||||
} while (restart);
|
} while (restart);
|
||||||
|
|
||||||
|
// unreserve pages later
|
||||||
|
struct PagesUnreserver {
|
||||||
|
PagesUnreserver(vm_page_reservation* reservation)
|
||||||
|
:
|
||||||
|
fReservation(reservation)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~PagesUnreserver()
|
||||||
|
{
|
||||||
|
if (fReservation != NULL)
|
||||||
|
vm_page_unreserve_pages(fReservation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
vm_page_reservation* fReservation;
|
||||||
|
} pagesUnreserver(wiredPages > 0 ? &wiredPagesReservation : NULL);
|
||||||
|
|
||||||
if (addressSpec == B_CLONE_ADDRESS) {
|
if (addressSpec == B_CLONE_ADDRESS) {
|
||||||
addressSpec = B_EXACT_ADDRESS;
|
addressSpec = B_EXACT_ADDRESS;
|
||||||
*_address = (void*)source->Base();
|
*_address = (void*)source->Base();
|
||||||
@@ -2296,8 +2379,10 @@ vm_copy_area(team_id team, const char* name, void** _address,
|
|||||||
if (!sharedArea) {
|
if (!sharedArea) {
|
||||||
if ((source->protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA)) != 0) {
|
if ((source->protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA)) != 0) {
|
||||||
// TODO: do something more useful if this fails!
|
// TODO: do something more useful if this fails!
|
||||||
if (vm_copy_on_write_area(cache) < B_OK)
|
if (vm_copy_on_write_area(cache,
|
||||||
|
wiredPages > 0 ? &wiredPagesReservation : NULL) < B_OK) {
|
||||||
panic("vm_copy_on_write_area() failed!\n");
|
panic("vm_copy_on_write_area() failed!\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2409,7 +2494,7 @@ vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection,
|
|||||||
// There are consumers -- we have to insert a new cache. Fortunately
|
// There are consumers -- we have to insert a new cache. Fortunately
|
||||||
// vm_copy_on_write_area() does everything that's needed.
|
// vm_copy_on_write_area() does everything that's needed.
|
||||||
changePageProtection = false;
|
changePageProtection = false;
|
||||||
status = vm_copy_on_write_area(cache);
|
status = vm_copy_on_write_area(cache, NULL);
|
||||||
} else {
|
} else {
|
||||||
// No consumers, so we don't need to insert a new one.
|
// No consumers, so we don't need to insert a new one.
|
||||||
if (cache->source != NULL && cache->temporary) {
|
if (cache->source != NULL && cache->temporary) {
|
||||||
@@ -2593,7 +2678,7 @@ vm_clear_page_mapping_accessed_flags(struct vm_page *page)
|
|||||||
int32
|
int32
|
||||||
vm_remove_all_page_mappings_if_unaccessed(struct vm_page *page)
|
vm_remove_all_page_mappings_if_unaccessed(struct vm_page *page)
|
||||||
{
|
{
|
||||||
ASSERT(page->wired_count == 0);
|
ASSERT(page->WiredCount() == 0);
|
||||||
|
|
||||||
if (page->accessed)
|
if (page->accessed)
|
||||||
return vm_clear_page_mapping_accessed_flags(page);
|
return vm_clear_page_mapping_accessed_flags(page);
|
||||||
|
|||||||
@@ -495,7 +495,7 @@ class SetPageState : public AbstractTraceEntry {
|
|||||||
fOldState(page->State()),
|
fOldState(page->State()),
|
||||||
fNewState(newState),
|
fNewState(newState),
|
||||||
fBusy(page->busy),
|
fBusy(page->busy),
|
||||||
fWired(page->wired_count > 0),
|
fWired(page->WiredCount() > 0),
|
||||||
fMapped(!page->mappings.IsEmpty()),
|
fMapped(!page->mappings.IsEmpty()),
|
||||||
fAccessed(page->accessed),
|
fAccessed(page->accessed),
|
||||||
fModified(page->modified)
|
fModified(page->modified)
|
||||||
@@ -698,7 +698,7 @@ dump_page(int argc, char **argv)
|
|||||||
kprintf("cache_offset: %" B_PRIuPHYSADDR "\n", page->cache_offset);
|
kprintf("cache_offset: %" B_PRIuPHYSADDR "\n", page->cache_offset);
|
||||||
kprintf("cache_next: %p\n", page->cache_next);
|
kprintf("cache_next: %p\n", page->cache_next);
|
||||||
kprintf("state: %s\n", page_state_to_string(page->State()));
|
kprintf("state: %s\n", page_state_to_string(page->State()));
|
||||||
kprintf("wired_count: %d\n", page->wired_count);
|
kprintf("wired_count: %d\n", page->WiredCount());
|
||||||
kprintf("usage_count: %d\n", page->usage_count);
|
kprintf("usage_count: %d\n", page->usage_count);
|
||||||
kprintf("busy: %d\n", page->busy);
|
kprintf("busy: %d\n", page->busy);
|
||||||
kprintf("busy_writing: %d\n", page->busy_writing);
|
kprintf("busy_writing: %d\n", page->busy_writing);
|
||||||
@@ -818,7 +818,7 @@ dump_page_queue(int argc, char **argv)
|
|||||||
for (i = 0; page; i++, page = queue->Next(page)) {
|
for (i = 0; page; i++, page = queue->Next(page)) {
|
||||||
kprintf("%p %p %-7s %8s %5d %5d\n", page, page->Cache(),
|
kprintf("%p %p %-7s %8s %5d %5d\n", page, page->Cache(),
|
||||||
type, page_state_to_string(page->State()),
|
type, page_state_to_string(page->State()),
|
||||||
page->wired_count, page->usage_count);
|
page->WiredCount(), page->usage_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -862,7 +862,7 @@ dump_page_stats(int argc, char **argv)
|
|||||||
|
|
||||||
if (pageState == PAGE_STATE_MODIFIED
|
if (pageState == PAGE_STATE_MODIFIED
|
||||||
&& sPages[i].Cache() != NULL
|
&& sPages[i].Cache() != NULL
|
||||||
&& sPages[i].Cache()->temporary && sPages[i].wired_count == 0) {
|
&& sPages[i].Cache()->temporary && sPages[i].WiredCount() == 0) {
|
||||||
swappableModified++;
|
swappableModified++;
|
||||||
if (sPages[i].usage_count == 0)
|
if (sPages[i].usage_count == 0)
|
||||||
swappableModifiedInactive++;
|
swappableModifiedInactive++;
|
||||||
@@ -948,7 +948,7 @@ dump_page_stats(int argc, char **argv)
|
|||||||
static void
|
static void
|
||||||
track_page_usage(vm_page* page)
|
track_page_usage(vm_page* page)
|
||||||
{
|
{
|
||||||
if (page->wired_count == 0) {
|
if (page->WiredCount() == 0) {
|
||||||
sNextPageUsage[(int32)page->usage_count + 128]++;
|
sNextPageUsage[(int32)page->usage_count + 128]++;
|
||||||
sNextPageUsagePageCount++;
|
sNextPageUsagePageCount++;
|
||||||
}
|
}
|
||||||
@@ -1981,7 +1981,7 @@ page_writer(void* /*unused*/)
|
|||||||
DEBUG_PAGE_ACCESS_START(page);
|
DEBUG_PAGE_ACCESS_START(page);
|
||||||
|
|
||||||
// Don't write back wired (locked) pages.
|
// Don't write back wired (locked) pages.
|
||||||
if (page->wired_count > 0) {
|
if (page->WiredCount() > 0) {
|
||||||
set_page_state(page, PAGE_STATE_ACTIVE);
|
set_page_state(page, PAGE_STATE_ACTIVE);
|
||||||
DEBUG_PAGE_ACCESS_END(page);
|
DEBUG_PAGE_ACCESS_END(page);
|
||||||
continue;
|
continue;
|
||||||
@@ -2073,7 +2073,7 @@ free_page_swap_space(int32 index)
|
|||||||
DEBUG_PAGE_ACCESS_START(page);
|
DEBUG_PAGE_ACCESS_START(page);
|
||||||
|
|
||||||
VMCache* cache = page->Cache();
|
VMCache* cache = page->Cache();
|
||||||
if (cache->temporary && page->wired_count == 0
|
if (cache->temporary && page->WiredCount() == 0
|
||||||
&& cache->HasPage(page->cache_offset << PAGE_SHIFT)
|
&& cache->HasPage(page->cache_offset << PAGE_SHIFT)
|
||||||
&& page->usage_count > 0) {
|
&& page->usage_count > 0) {
|
||||||
// TODO: how to judge a page is highly active?
|
// TODO: how to judge a page is highly active?
|
||||||
@@ -2242,9 +2242,10 @@ idle_scan_active_pages(page_stats& pageStats)
|
|||||||
// wouldn't notice when those would become unused and could thus be
|
// wouldn't notice when those would become unused and could thus be
|
||||||
// moved to the cached list.
|
// moved to the cached list.
|
||||||
int32 usageCount;
|
int32 usageCount;
|
||||||
if (page->wired_count > 0 || page->usage_count > 0 || !cache->temporary)
|
if (page->WiredCount() > 0 || page->usage_count > 0
|
||||||
|
|| !cache->temporary) {
|
||||||
usageCount = vm_clear_page_mapping_accessed_flags(page);
|
usageCount = vm_clear_page_mapping_accessed_flags(page);
|
||||||
else
|
} else
|
||||||
usageCount = vm_remove_all_page_mappings_if_unaccessed(page);
|
usageCount = vm_remove_all_page_mappings_if_unaccessed(page);
|
||||||
|
|
||||||
if (usageCount > 0) {
|
if (usageCount > 0) {
|
||||||
@@ -2333,7 +2334,7 @@ full_scan_inactive_pages(page_stats& pageStats, int32 despairLevel)
|
|||||||
// Get the accessed count, clear the accessed/modified flags and
|
// Get the accessed count, clear the accessed/modified flags and
|
||||||
// unmap the page, if it hasn't been accessed.
|
// unmap the page, if it hasn't been accessed.
|
||||||
int32 usageCount;
|
int32 usageCount;
|
||||||
if (page->wired_count > 0)
|
if (page->WiredCount() > 0)
|
||||||
usageCount = vm_clear_page_mapping_accessed_flags(page);
|
usageCount = vm_clear_page_mapping_accessed_flags(page);
|
||||||
else
|
else
|
||||||
usageCount = vm_remove_all_page_mappings_if_unaccessed(page);
|
usageCount = vm_remove_all_page_mappings_if_unaccessed(page);
|
||||||
@@ -2869,19 +2870,7 @@ vm_page_init(kernel_args *args)
|
|||||||
|
|
||||||
// initialize the free page table
|
// initialize the free page table
|
||||||
for (uint32 i = 0; i < sNumPages; i++) {
|
for (uint32 i = 0; i < sNumPages; i++) {
|
||||||
sPages[i].physical_page_number = sPhysicalPageOffset + i;
|
sPages[i].Init(sPhysicalPageOffset + i);
|
||||||
sPages[i].InitState(PAGE_STATE_FREE);
|
|
||||||
new(&sPages[i].mappings) vm_page_mappings();
|
|
||||||
sPages[i].wired_count = 0;
|
|
||||||
sPages[i].usage_count = 0;
|
|
||||||
sPages[i].busy_writing = false;
|
|
||||||
sPages[i].SetCacheRef(NULL);
|
|
||||||
#if DEBUG_PAGE_QUEUE
|
|
||||||
sPages[i].queue = NULL;
|
|
||||||
#endif
|
|
||||||
#if DEBUG_PAGE_ACCESS
|
|
||||||
sPages[i].accessing_thread = -1;
|
|
||||||
#endif
|
|
||||||
sFreePageQueue.Append(&sPages[i]);
|
sFreePageQueue.Append(&sPages[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user