kernel/vm: Move committed_size to the cache implementations.
This fixes a long-standing TODO, and a major inconsistency that for different caches, "commitment" reserves from different pools, so any two aren't necessarily convertible. The new system introduces a virtual method "TakeCommitmentFrom", which allows the VM's cut_area routine to behave as it did previously.
This commit is contained in:
@@ -147,9 +147,10 @@ public:
|
||||
|
||||
status_t SetMinimalCommitment(off_t commitment,
|
||||
int priority);
|
||||
off_t Commitment() const;
|
||||
virtual off_t Commitment() const;
|
||||
virtual bool CanOvercommit();
|
||||
virtual status_t Commit(off_t size, int priority);
|
||||
virtual void TakeCommitmentFrom(VMCache* from, off_t commitment);
|
||||
|
||||
// backing store operations
|
||||
virtual bool StoreHasPage(off_t offset);
|
||||
@@ -206,8 +207,6 @@ public:
|
||||
VMCache* source;
|
||||
off_t virtual_base;
|
||||
off_t virtual_end;
|
||||
off_t committed_size;
|
||||
// TODO: Remove!
|
||||
uint32 page_count;
|
||||
uint32 temporary : 1;
|
||||
uint32 type : 6;
|
||||
|
||||
@@ -452,7 +452,7 @@ VMAnonymousCache::~VMAnonymousCache()
|
||||
|
||||
_FreeSwapPageRange(virtual_base, virtual_end, false);
|
||||
swap_space_unreserve(fReservedSwapSize);
|
||||
vm_unreserve_memory_or_swap(committed_size);
|
||||
vm_unreserve_memory_or_swap(fCommittedSize);
|
||||
}
|
||||
|
||||
|
||||
@@ -469,6 +469,7 @@ VMAnonymousCache::Init(bool canOvercommit, int32 numPrecommittedPages,
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
fCommittedSize = 0;
|
||||
fCanOvercommit = canOvercommit;
|
||||
fHasPrecommitted = false;
|
||||
fPrecommittedPages = min_c(numPrecommittedPages, 255);
|
||||
@@ -612,7 +613,7 @@ VMAnonymousCache::Discard(off_t offset, off_t size)
|
||||
_FreeSwapPageRange(offset, offset + size);
|
||||
const ssize_t discarded = VMCache::Discard(offset, size);
|
||||
if (discarded > 0 && fCanOvercommit)
|
||||
Commit(committed_size - discarded, VM_PRIORITY_USER);
|
||||
Commit(fCommittedSize - discarded, VM_PRIORITY_USER);
|
||||
return discarded;
|
||||
}
|
||||
|
||||
@@ -724,14 +725,28 @@ VMAnonymousCache::Adopt(VMCache* _source, off_t offset, off_t size,
|
||||
// We need to adopt the commitment for these pages.
|
||||
uint32 newPages = page_count - initialPageCount;
|
||||
off_t pagesCommitment = newPages * B_PAGE_SIZE;
|
||||
source->committed_size -= pagesCommitment;
|
||||
committed_size += pagesCommitment;
|
||||
source->fCommittedSize -= pagesCommitment;
|
||||
fCommittedSize += pagesCommitment;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
off_t
|
||||
VMAnonymousCache::Commitment() const
|
||||
{
|
||||
return fCommittedSize;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
VMAnonymousCache::CanOvercommit()
|
||||
{
|
||||
return fCanOvercommit;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VMAnonymousCache::Commit(off_t size, int priority)
|
||||
{
|
||||
@@ -743,7 +758,7 @@ VMAnonymousCache::Commit(off_t size, int priority)
|
||||
|
||||
// If we can overcommit, we don't commit here, but in Fault(). We always
|
||||
// unreserve memory, if we're asked to shrink our commitment, though.
|
||||
if (fCanOvercommit && size > committed_size) {
|
||||
if (fCanOvercommit && size > fCommittedSize) {
|
||||
if (fHasPrecommitted)
|
||||
return B_OK;
|
||||
|
||||
@@ -754,31 +769,37 @@ VMAnonymousCache::Commit(off_t size, int priority)
|
||||
size = precommitted;
|
||||
|
||||
// pre-commit should not shrink existing commitment
|
||||
size += committed_size;
|
||||
size += fCommittedSize;
|
||||
}
|
||||
|
||||
// Check to see how much we could commit - we need real memory
|
||||
|
||||
if (size > committed_size) {
|
||||
if (size > fCommittedSize) {
|
||||
// try to commit
|
||||
if (vm_try_reserve_memory_or_swap(size - committed_size, priority, 1000000)
|
||||
if (vm_try_reserve_memory_or_swap(size - fCommittedSize, priority, 1000000)
|
||||
!= B_OK) {
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
} else {
|
||||
// we can release some
|
||||
vm_unreserve_memory_or_swap(committed_size - size);
|
||||
vm_unreserve_memory_or_swap(fCommittedSize - size);
|
||||
}
|
||||
|
||||
committed_size = size;
|
||||
fCommittedSize = size;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
VMAnonymousCache::CanOvercommit()
|
||||
void
|
||||
VMAnonymousCache::TakeCommitmentFrom(VMCache* _from, off_t commitment)
|
||||
{
|
||||
return fCanOvercommit;
|
||||
VMAnonymousCache* from = dynamic_cast<VMAnonymousCache*>(_from);
|
||||
ASSERT(from != NULL && from->fCommittedSize >= commitment);
|
||||
AssertLocked();
|
||||
from->AssertLocked();
|
||||
|
||||
from->fCommittedSize -= commitment;
|
||||
fCommittedSize += commitment;
|
||||
}
|
||||
|
||||
|
||||
@@ -1046,7 +1067,7 @@ VMAnonymousCache::Fault(struct VMAddressSpace* aspace, off_t offset)
|
||||
if (fCanOvercommit && LookupPage(offset) == NULL && !StoreHasPage(offset)) {
|
||||
if (fPrecommittedPages == 0) {
|
||||
// never commit more than needed
|
||||
if (committed_size / B_PAGE_SIZE > page_count)
|
||||
if (fCommittedSize / B_PAGE_SIZE > page_count)
|
||||
return B_BAD_HANDLER;
|
||||
|
||||
// try to commit additional memory
|
||||
@@ -1058,7 +1079,7 @@ VMAnonymousCache::Fault(struct VMAddressSpace* aspace, off_t offset)
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
committed_size += B_PAGE_SIZE;
|
||||
fCommittedSize += B_PAGE_SIZE;
|
||||
} else
|
||||
fPrecommittedPages--;
|
||||
}
|
||||
@@ -1079,13 +1100,13 @@ VMAnonymousCache::Merge(VMCache* _source)
|
||||
}
|
||||
|
||||
// take over the source's committed size
|
||||
committed_size += source->committed_size;
|
||||
source->committed_size = 0;
|
||||
fCommittedSize += source->fCommittedSize;
|
||||
source->fCommittedSize = 0;
|
||||
|
||||
off_t actualSize = PAGE_ALIGN(virtual_end - virtual_base);
|
||||
if (committed_size > actualSize) {
|
||||
vm_unreserve_memory_or_swap(committed_size - actualSize);
|
||||
committed_size = actualSize;
|
||||
if (fCommittedSize > actualSize) {
|
||||
vm_unreserve_memory_or_swap(fCommittedSize - actualSize);
|
||||
fCommittedSize = actualSize;
|
||||
}
|
||||
|
||||
// Move all not shadowed swap pages from the source to the consumer cache.
|
||||
|
||||
@@ -48,8 +48,11 @@ public:
|
||||
|
||||
virtual ssize_t Discard(off_t offset, off_t size);
|
||||
|
||||
virtual off_t Commitment() const;
|
||||
virtual bool CanOvercommit();
|
||||
virtual status_t Commit(off_t size, int priority);
|
||||
virtual void TakeCommitmentFrom(VMCache* from, off_t commitment);
|
||||
|
||||
virtual bool StoreHasPage(off_t offset);
|
||||
virtual bool DebugStoreHasPage(off_t offset);
|
||||
|
||||
@@ -100,6 +103,7 @@ private:
|
||||
private:
|
||||
friend bool swap_free_page_swap_space(vm_page* page);
|
||||
|
||||
off_t fCommittedSize;
|
||||
bool fCanOvercommit;
|
||||
bool fHasPrecommitted;
|
||||
uint8 fPrecommittedPages;
|
||||
|
||||
@@ -49,6 +49,7 @@ VMAnonymousNoSwapCache::Init(bool canOvercommit, int32 numPrecommittedPages,
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
committed_size = 0;
|
||||
fCanOvercommit = canOvercommit;
|
||||
fHasPrecommitted = false;
|
||||
fPrecommittedPages = min_c(numPrecommittedPages, 255);
|
||||
@@ -59,14 +60,19 @@ VMAnonymousNoSwapCache::Init(bool canOvercommit, int32 numPrecommittedPages,
|
||||
|
||||
|
||||
status_t
|
||||
VMAnonymousNoSwapCache::Adopt(VMCache* from, off_t offset, off_t size,
|
||||
VMAnonymousNoSwapCache::Adopt(VMCache* _from, off_t offset, off_t size,
|
||||
off_t newOffset)
|
||||
{
|
||||
VMAnonymousNoSwapCache* from = dynamic_cast<VMAnonymousNoSwapCache*>(_from);
|
||||
ASSERT(from != NULL);
|
||||
|
||||
uint32 initialPageCount = page_count;
|
||||
status_t status = VMCache::Adopt(from, offset, size, newOffset);
|
||||
|
||||
if (fCanOvercommit) {
|
||||
// We need to adopt the commitment for these pages.
|
||||
ASSERT(from->fCanOvercommit);
|
||||
|
||||
uint32 newPages = page_count - initialPageCount;
|
||||
off_t pagesCommitment = newPages * B_PAGE_SIZE;
|
||||
from->committed_size -= pagesCommitment;
|
||||
@@ -87,6 +93,20 @@ VMAnonymousNoSwapCache::Discard(off_t offset, off_t size)
|
||||
}
|
||||
|
||||
|
||||
off_t
|
||||
VMAnonymousNoSwapCache::Commitment() const
|
||||
{
|
||||
return committed_size;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
VMAnonymousNoSwapCache::CanOvercommit()
|
||||
{
|
||||
return fCanOvercommit;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VMAnonymousNoSwapCache::Commit(off_t size, int priority)
|
||||
{
|
||||
@@ -127,10 +147,16 @@ VMAnonymousNoSwapCache::Commit(off_t size, int priority)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
VMAnonymousNoSwapCache::CanOvercommit()
|
||||
void
|
||||
VMAnonymousNoSwapCache::TakeCommitmentFrom(VMCache* _from, off_t commitment)
|
||||
{
|
||||
return fCanOvercommit;
|
||||
VMAnonymousNoSwapCache* from = dynamic_cast<VMAnonymousNoSwapCache*>(_from);
|
||||
ASSERT(from != NULL && from->committed_size >= commitment);
|
||||
AssertLocked();
|
||||
from->AssertLocked();
|
||||
|
||||
from->committed_size -= commitment;
|
||||
committed_size += commitment;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -26,8 +26,11 @@ public:
|
||||
off_t newOffset);
|
||||
virtual ssize_t Discard(off_t offset, off_t size);
|
||||
|
||||
virtual off_t Commitment() const;
|
||||
virtual bool CanOvercommit();
|
||||
virtual status_t Commit(off_t size, int priority);
|
||||
virtual void TakeCommitmentFrom(VMCache* from, off_t commitment);
|
||||
|
||||
virtual bool StoreHasPage(off_t offset);
|
||||
|
||||
virtual int32 GuardSize() { return fGuardedSize; }
|
||||
@@ -49,6 +52,9 @@ public:
|
||||
protected:
|
||||
virtual void DeleteObject();
|
||||
|
||||
public:
|
||||
off_t committed_size;
|
||||
|
||||
private:
|
||||
bool fCanOvercommit;
|
||||
bool fHasPrecommitted;
|
||||
|
||||
@@ -638,7 +638,6 @@ VMCache::Init(const char* name, uint32 cacheType, uint32 allocationFlags)
|
||||
source = NULL;
|
||||
virtual_base = 0;
|
||||
virtual_end = 0;
|
||||
committed_size = 0;
|
||||
temporary = 0;
|
||||
page_count = 0;
|
||||
fWiredPagesCount = 0;
|
||||
@@ -1310,7 +1309,7 @@ VMCache::FlushAndRemoveAllPages()
|
||||
off_t
|
||||
VMCache::Commitment() const
|
||||
{
|
||||
return committed_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1329,6 +1328,13 @@ VMCache::Commit(off_t size, int priority)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VMCache::TakeCommitmentFrom(VMCache* from, off_t commitment)
|
||||
{
|
||||
ASSERT_UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
/*! Returns whether the cache's underlying backing store could deliver the
|
||||
page at the given offset.
|
||||
|
||||
|
||||
+15
-15
@@ -969,9 +969,8 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
||||
if (!overcommitting && resizePriority != -1) {
|
||||
// Steal some of the original cache's commitment.
|
||||
const size_t steal = PAGE_ALIGN(secondSize);
|
||||
if (cache->committed_size > (off_t)steal) {
|
||||
cache->committed_size -= steal;
|
||||
secondCache->committed_size += steal;
|
||||
if (cache->Commitment() > (off_t)steal) {
|
||||
secondCache->TakeCommitmentFrom(cache, steal);
|
||||
commitmentStolen = steal;
|
||||
}
|
||||
}
|
||||
@@ -1001,8 +1000,7 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
||||
}
|
||||
|
||||
if (error != B_OK) {
|
||||
secondCache->committed_size -= commitmentStolen;
|
||||
cache->committed_size += commitmentStolen;
|
||||
cache->TakeCommitmentFrom(secondCache, commitmentStolen);
|
||||
|
||||
// Move the pages back.
|
||||
status_t readoptStatus = cache->Adopt(secondCache,
|
||||
@@ -1036,9 +1034,9 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
||||
if (resizePriority == -1) {
|
||||
// Adjust commitments.
|
||||
const off_t areaCommit = compute_area_page_commitment(area) * B_PAGE_SIZE;
|
||||
if (areaCommit < area->cache->committed_size) {
|
||||
secondArea->cache->committed_size += area->cache->committed_size - areaCommit;
|
||||
area->cache->committed_size = areaCommit;
|
||||
if (areaCommit < area->cache->Commitment()) {
|
||||
secondArea->cache->TakeCommitmentFrom(area->cache,
|
||||
area->cache->Commitment() - areaCommit);
|
||||
}
|
||||
area->cache->Commit(areaCommit, priority);
|
||||
|
||||
@@ -1768,9 +1766,12 @@ vm_create_anonymous_area(team_id team, const char *name, addr_t size,
|
||||
|
||||
cache->temporary = 1;
|
||||
cache->virtual_end = size;
|
||||
cache->committed_size = reservedMemory;
|
||||
// TODO: This should be done via a method.
|
||||
|
||||
if (reservedMemory != 0) {
|
||||
VMAnonymousNoSwapCache* noSwapCache = dynamic_cast<VMAnonymousNoSwapCache*>(cache);
|
||||
noSwapCache->committed_size = reservedMemory;
|
||||
reservedMemory = 0;
|
||||
}
|
||||
|
||||
cache->Lock();
|
||||
|
||||
@@ -2864,16 +2865,15 @@ vm_copy_on_write_area(VMCache* lowerCache,
|
||||
|
||||
// Shrink the lower cache's commitment (if possible) and steal the remainder;
|
||||
// and increase the upper cache's commitment to the lower cache's old commitment.
|
||||
const off_t lowerOldCommitment = lowerCache->committed_size,
|
||||
const off_t lowerOldCommitment = lowerCache->Commitment(),
|
||||
lowerNewCommitment = (lowerCache->page_count * B_PAGE_SIZE);
|
||||
if (lowerNewCommitment < lowerOldCommitment) {
|
||||
lowerCache->committed_size = lowerNewCommitment;
|
||||
upperCache->committed_size = lowerOldCommitment - lowerNewCommitment;
|
||||
upperCache->TakeCommitmentFrom(lowerCache,
|
||||
lowerOldCommitment - lowerNewCommitment);
|
||||
}
|
||||
status = upperCache->Commit(lowerOldCommitment, VM_PRIORITY_USER);
|
||||
if (status != B_OK) {
|
||||
lowerCache->committed_size += upperCache->committed_size;
|
||||
upperCache->committed_size = 0;
|
||||
lowerCache->TakeCommitmentFrom(upperCache, upperCache->Commitment());
|
||||
upperCache->ReleaseRefAndUnlock();
|
||||
return status;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user