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,
|
status_t SetMinimalCommitment(off_t commitment,
|
||||||
int priority);
|
int priority);
|
||||||
off_t Commitment() const;
|
virtual off_t Commitment() const;
|
||||||
virtual bool CanOvercommit();
|
virtual bool CanOvercommit();
|
||||||
virtual status_t Commit(off_t size, int priority);
|
virtual status_t Commit(off_t size, int priority);
|
||||||
|
virtual void TakeCommitmentFrom(VMCache* from, off_t commitment);
|
||||||
|
|
||||||
// backing store operations
|
// backing store operations
|
||||||
virtual bool StoreHasPage(off_t offset);
|
virtual bool StoreHasPage(off_t offset);
|
||||||
@@ -206,8 +207,6 @@ public:
|
|||||||
VMCache* source;
|
VMCache* source;
|
||||||
off_t virtual_base;
|
off_t virtual_base;
|
||||||
off_t virtual_end;
|
off_t virtual_end;
|
||||||
off_t committed_size;
|
|
||||||
// TODO: Remove!
|
|
||||||
uint32 page_count;
|
uint32 page_count;
|
||||||
uint32 temporary : 1;
|
uint32 temporary : 1;
|
||||||
uint32 type : 6;
|
uint32 type : 6;
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ VMAnonymousCache::~VMAnonymousCache()
|
|||||||
|
|
||||||
_FreeSwapPageRange(virtual_base, virtual_end, false);
|
_FreeSwapPageRange(virtual_base, virtual_end, false);
|
||||||
swap_space_unreserve(fReservedSwapSize);
|
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)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
fCommittedSize = 0;
|
||||||
fCanOvercommit = canOvercommit;
|
fCanOvercommit = canOvercommit;
|
||||||
fHasPrecommitted = false;
|
fHasPrecommitted = false;
|
||||||
fPrecommittedPages = min_c(numPrecommittedPages, 255);
|
fPrecommittedPages = min_c(numPrecommittedPages, 255);
|
||||||
@@ -612,7 +613,7 @@ VMAnonymousCache::Discard(off_t offset, off_t size)
|
|||||||
_FreeSwapPageRange(offset, offset + size);
|
_FreeSwapPageRange(offset, offset + size);
|
||||||
const ssize_t discarded = VMCache::Discard(offset, size);
|
const ssize_t discarded = VMCache::Discard(offset, size);
|
||||||
if (discarded > 0 && fCanOvercommit)
|
if (discarded > 0 && fCanOvercommit)
|
||||||
Commit(committed_size - discarded, VM_PRIORITY_USER);
|
Commit(fCommittedSize - discarded, VM_PRIORITY_USER);
|
||||||
return discarded;
|
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.
|
// We need to adopt the commitment for these pages.
|
||||||
uint32 newPages = page_count - initialPageCount;
|
uint32 newPages = page_count - initialPageCount;
|
||||||
off_t pagesCommitment = newPages * B_PAGE_SIZE;
|
off_t pagesCommitment = newPages * B_PAGE_SIZE;
|
||||||
source->committed_size -= pagesCommitment;
|
source->fCommittedSize -= pagesCommitment;
|
||||||
committed_size += pagesCommitment;
|
fCommittedSize += pagesCommitment;
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
off_t
|
||||||
|
VMAnonymousCache::Commitment() const
|
||||||
|
{
|
||||||
|
return fCommittedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
VMAnonymousCache::CanOvercommit()
|
||||||
|
{
|
||||||
|
return fCanOvercommit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
VMAnonymousCache::Commit(off_t size, int priority)
|
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
|
// 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.
|
// unreserve memory, if we're asked to shrink our commitment, though.
|
||||||
if (fCanOvercommit && size > committed_size) {
|
if (fCanOvercommit && size > fCommittedSize) {
|
||||||
if (fHasPrecommitted)
|
if (fHasPrecommitted)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
@@ -754,31 +769,37 @@ VMAnonymousCache::Commit(off_t size, int priority)
|
|||||||
size = precommitted;
|
size = precommitted;
|
||||||
|
|
||||||
// pre-commit should not shrink existing commitment
|
// pre-commit should not shrink existing commitment
|
||||||
size += committed_size;
|
size += fCommittedSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see how much we could commit - we need real memory
|
// Check to see how much we could commit - we need real memory
|
||||||
|
|
||||||
if (size > committed_size) {
|
if (size > fCommittedSize) {
|
||||||
// try to commit
|
// 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) {
|
!= B_OK) {
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// we can release some
|
// 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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
void
|
||||||
VMAnonymousCache::CanOvercommit()
|
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 (fCanOvercommit && LookupPage(offset) == NULL && !StoreHasPage(offset)) {
|
||||||
if (fPrecommittedPages == 0) {
|
if (fPrecommittedPages == 0) {
|
||||||
// never commit more than needed
|
// never commit more than needed
|
||||||
if (committed_size / B_PAGE_SIZE > page_count)
|
if (fCommittedSize / B_PAGE_SIZE > page_count)
|
||||||
return B_BAD_HANDLER;
|
return B_BAD_HANDLER;
|
||||||
|
|
||||||
// try to commit additional memory
|
// try to commit additional memory
|
||||||
@@ -1058,7 +1079,7 @@ VMAnonymousCache::Fault(struct VMAddressSpace* aspace, off_t offset)
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
committed_size += B_PAGE_SIZE;
|
fCommittedSize += B_PAGE_SIZE;
|
||||||
} else
|
} else
|
||||||
fPrecommittedPages--;
|
fPrecommittedPages--;
|
||||||
}
|
}
|
||||||
@@ -1079,13 +1100,13 @@ VMAnonymousCache::Merge(VMCache* _source)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// take over the source's committed size
|
// take over the source's committed size
|
||||||
committed_size += source->committed_size;
|
fCommittedSize += source->fCommittedSize;
|
||||||
source->committed_size = 0;
|
source->fCommittedSize = 0;
|
||||||
|
|
||||||
off_t actualSize = PAGE_ALIGN(virtual_end - virtual_base);
|
off_t actualSize = PAGE_ALIGN(virtual_end - virtual_base);
|
||||||
if (committed_size > actualSize) {
|
if (fCommittedSize > actualSize) {
|
||||||
vm_unreserve_memory_or_swap(committed_size - actualSize);
|
vm_unreserve_memory_or_swap(fCommittedSize - actualSize);
|
||||||
committed_size = actualSize;
|
fCommittedSize = actualSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move all not shadowed swap pages from the source to the consumer cache.
|
// 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 ssize_t Discard(off_t offset, off_t size);
|
||||||
|
|
||||||
|
virtual off_t Commitment() const;
|
||||||
virtual bool CanOvercommit();
|
virtual bool CanOvercommit();
|
||||||
virtual status_t Commit(off_t size, int priority);
|
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 StoreHasPage(off_t offset);
|
||||||
virtual bool DebugStoreHasPage(off_t offset);
|
virtual bool DebugStoreHasPage(off_t offset);
|
||||||
|
|
||||||
@@ -100,6 +103,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
friend bool swap_free_page_swap_space(vm_page* page);
|
friend bool swap_free_page_swap_space(vm_page* page);
|
||||||
|
|
||||||
|
off_t fCommittedSize;
|
||||||
bool fCanOvercommit;
|
bool fCanOvercommit;
|
||||||
bool fHasPrecommitted;
|
bool fHasPrecommitted;
|
||||||
uint8 fPrecommittedPages;
|
uint8 fPrecommittedPages;
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ VMAnonymousNoSwapCache::Init(bool canOvercommit, int32 numPrecommittedPages,
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
committed_size = 0;
|
||||||
fCanOvercommit = canOvercommit;
|
fCanOvercommit = canOvercommit;
|
||||||
fHasPrecommitted = false;
|
fHasPrecommitted = false;
|
||||||
fPrecommittedPages = min_c(numPrecommittedPages, 255);
|
fPrecommittedPages = min_c(numPrecommittedPages, 255);
|
||||||
@@ -59,14 +60,19 @@ VMAnonymousNoSwapCache::Init(bool canOvercommit, int32 numPrecommittedPages,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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)
|
off_t newOffset)
|
||||||
{
|
{
|
||||||
|
VMAnonymousNoSwapCache* from = dynamic_cast<VMAnonymousNoSwapCache*>(_from);
|
||||||
|
ASSERT(from != NULL);
|
||||||
|
|
||||||
uint32 initialPageCount = page_count;
|
uint32 initialPageCount = page_count;
|
||||||
status_t status = VMCache::Adopt(from, offset, size, newOffset);
|
status_t status = VMCache::Adopt(from, offset, size, newOffset);
|
||||||
|
|
||||||
if (fCanOvercommit) {
|
if (fCanOvercommit) {
|
||||||
// We need to adopt the commitment for these pages.
|
// We need to adopt the commitment for these pages.
|
||||||
|
ASSERT(from->fCanOvercommit);
|
||||||
|
|
||||||
uint32 newPages = page_count - initialPageCount;
|
uint32 newPages = page_count - initialPageCount;
|
||||||
off_t pagesCommitment = newPages * B_PAGE_SIZE;
|
off_t pagesCommitment = newPages * B_PAGE_SIZE;
|
||||||
from->committed_size -= pagesCommitment;
|
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
|
status_t
|
||||||
VMAnonymousNoSwapCache::Commit(off_t size, int priority)
|
VMAnonymousNoSwapCache::Commit(off_t size, int priority)
|
||||||
{
|
{
|
||||||
@@ -127,10 +147,16 @@ VMAnonymousNoSwapCache::Commit(off_t size, int priority)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
void
|
||||||
VMAnonymousNoSwapCache::CanOvercommit()
|
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);
|
off_t newOffset);
|
||||||
virtual ssize_t Discard(off_t offset, off_t size);
|
virtual ssize_t Discard(off_t offset, off_t size);
|
||||||
|
|
||||||
|
virtual off_t Commitment() const;
|
||||||
virtual bool CanOvercommit();
|
virtual bool CanOvercommit();
|
||||||
virtual status_t Commit(off_t size, int priority);
|
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 StoreHasPage(off_t offset);
|
||||||
|
|
||||||
virtual int32 GuardSize() { return fGuardedSize; }
|
virtual int32 GuardSize() { return fGuardedSize; }
|
||||||
@@ -49,6 +52,9 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
virtual void DeleteObject();
|
virtual void DeleteObject();
|
||||||
|
|
||||||
|
public:
|
||||||
|
off_t committed_size;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool fCanOvercommit;
|
bool fCanOvercommit;
|
||||||
bool fHasPrecommitted;
|
bool fHasPrecommitted;
|
||||||
|
|||||||
@@ -638,7 +638,6 @@ VMCache::Init(const char* name, uint32 cacheType, uint32 allocationFlags)
|
|||||||
source = NULL;
|
source = NULL;
|
||||||
virtual_base = 0;
|
virtual_base = 0;
|
||||||
virtual_end = 0;
|
virtual_end = 0;
|
||||||
committed_size = 0;
|
|
||||||
temporary = 0;
|
temporary = 0;
|
||||||
page_count = 0;
|
page_count = 0;
|
||||||
fWiredPagesCount = 0;
|
fWiredPagesCount = 0;
|
||||||
@@ -1310,7 +1309,7 @@ VMCache::FlushAndRemoveAllPages()
|
|||||||
off_t
|
off_t
|
||||||
VMCache::Commitment() const
|
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
|
/*! Returns whether the cache's underlying backing store could deliver the
|
||||||
page at the given offset.
|
page at the given offset.
|
||||||
|
|
||||||
|
|||||||
+16
-16
@@ -969,9 +969,8 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
|||||||
if (!overcommitting && resizePriority != -1) {
|
if (!overcommitting && resizePriority != -1) {
|
||||||
// Steal some of the original cache's commitment.
|
// Steal some of the original cache's commitment.
|
||||||
const size_t steal = PAGE_ALIGN(secondSize);
|
const size_t steal = PAGE_ALIGN(secondSize);
|
||||||
if (cache->committed_size > (off_t)steal) {
|
if (cache->Commitment() > (off_t)steal) {
|
||||||
cache->committed_size -= steal;
|
secondCache->TakeCommitmentFrom(cache, steal);
|
||||||
secondCache->committed_size += steal;
|
|
||||||
commitmentStolen = steal;
|
commitmentStolen = steal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1001,8 +1000,7 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
secondCache->committed_size -= commitmentStolen;
|
cache->TakeCommitmentFrom(secondCache, commitmentStolen);
|
||||||
cache->committed_size += commitmentStolen;
|
|
||||||
|
|
||||||
// Move the pages back.
|
// Move the pages back.
|
||||||
status_t readoptStatus = cache->Adopt(secondCache,
|
status_t readoptStatus = cache->Adopt(secondCache,
|
||||||
@@ -1036,9 +1034,9 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
|||||||
if (resizePriority == -1) {
|
if (resizePriority == -1) {
|
||||||
// Adjust commitments.
|
// Adjust commitments.
|
||||||
const off_t areaCommit = compute_area_page_commitment(area) * B_PAGE_SIZE;
|
const off_t areaCommit = compute_area_page_commitment(area) * B_PAGE_SIZE;
|
||||||
if (areaCommit < area->cache->committed_size) {
|
if (areaCommit < area->cache->Commitment()) {
|
||||||
secondArea->cache->committed_size += area->cache->committed_size - areaCommit;
|
secondArea->cache->TakeCommitmentFrom(area->cache,
|
||||||
area->cache->committed_size = areaCommit;
|
area->cache->Commitment() - areaCommit);
|
||||||
}
|
}
|
||||||
area->cache->Commit(areaCommit, priority);
|
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->temporary = 1;
|
||||||
cache->virtual_end = size;
|
cache->virtual_end = size;
|
||||||
cache->committed_size = reservedMemory;
|
|
||||||
// TODO: This should be done via a method.
|
if (reservedMemory != 0) {
|
||||||
reservedMemory = 0;
|
VMAnonymousNoSwapCache* noSwapCache = dynamic_cast<VMAnonymousNoSwapCache*>(cache);
|
||||||
|
noSwapCache->committed_size = reservedMemory;
|
||||||
|
reservedMemory = 0;
|
||||||
|
}
|
||||||
|
|
||||||
cache->Lock();
|
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;
|
// 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.
|
// 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);
|
lowerNewCommitment = (lowerCache->page_count * B_PAGE_SIZE);
|
||||||
if (lowerNewCommitment < lowerOldCommitment) {
|
if (lowerNewCommitment < lowerOldCommitment) {
|
||||||
lowerCache->committed_size = lowerNewCommitment;
|
upperCache->TakeCommitmentFrom(lowerCache,
|
||||||
upperCache->committed_size = lowerOldCommitment - lowerNewCommitment;
|
lowerOldCommitment - lowerNewCommitment);
|
||||||
}
|
}
|
||||||
status = upperCache->Commit(lowerOldCommitment, VM_PRIORITY_USER);
|
status = upperCache->Commit(lowerOldCommitment, VM_PRIORITY_USER);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
lowerCache->committed_size += upperCache->committed_size;
|
lowerCache->TakeCommitmentFrom(upperCache, upperCache->Commitment());
|
||||||
upperCache->committed_size = 0;
|
|
||||||
upperCache->ReleaseRefAndUnlock();
|
upperCache->ReleaseRefAndUnlock();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user