From b592ba6662b1ed6e04a80dafbda17c349aa53fa8 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Wed, 11 Dec 2024 14:19:06 -0500 Subject: [PATCH] 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 --- src/system/kernel/vm/vm.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 0a01386dee..1b4aa83156 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -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);