kernel/vm: Set the upper cache's commitment in vm_copy_on_write_area.

Otherwise we may fault later but have no memory to satisfy the fault.

For a compile of HaikuDepot and the mime_db in VMware with -j4, this
seems to increase the wait time on the "available memory" lock from
~0.1s to ~0.5s, and the wait count from ~500 to ~1500 (overall real time
~30s.) Probably we can mitigate that later by doing atomic updates on
sAvailableMemory, at least for releasing memory.

Change-Id: I61abc28d1fc30f7b3d5fd9a2e68e4f4ec960f88d
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8677
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Augustin Cavalier
2024-12-13 23:50:35 +00:00
committed by waddlesplash
parent 2acb67eef0
commit b592ba6662
+17 -2
View File
@@ -2735,14 +2735,13 @@ static status_t
vm_copy_on_write_area(VMCache* lowerCache,
vm_page_reservation* wiredPagesReservation)
{
VMCache* upperCache;
TRACE(("vm_copy_on_write_area(cache = %p)\n", lowerCache));
// We need to separate the cache from its areas. The cache goes one level
// deeper and we create a new cache inbetween.
// create an anonymous cache
VMCache* upperCache;
status_t status = VMCacheFactory::CreateAnonymousCache(upperCache,
lowerCache->CanOvercommit(), 0,
lowerCache->GuardSize() / B_PAGE_SIZE,
@@ -2757,6 +2756,22 @@ vm_copy_on_write_area(VMCache* lowerCache,
upperCache->virtual_base = lowerCache->virtual_base;
upperCache->virtual_end = lowerCache->virtual_end;
// 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,
lowerNewCommitment = (lowerCache->page_count * B_PAGE_SIZE);
if (lowerNewCommitment < lowerOldCommitment) {
lowerCache->committed_size = lowerNewCommitment;
upperCache->committed_size = lowerOldCommitment - lowerNewCommitment;
}
status = upperCache->Commit(lowerOldCommitment, VM_PRIORITY_USER);
if (status != B_OK) {
lowerCache->committed_size += upperCache->committed_size;
upperCache->committed_size = 0;
upperCache->ReleaseRefAndUnlock();
return status;
}
// transfer the lower cache areas to the upper cache
rw_lock_write_lock(&sAreaCacheLock);
upperCache->TransferAreas(lowerCache);