diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 1b4aa83156..feb362a806 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -1120,12 +1120,31 @@ discard_area_range(VMArea* area, addr_t address, addr_t size) unmap_pages(area, address, size); + ssize_t commitmentChange = 0; + if (cache->temporary && !cache->CanOvercommit() && area->page_protections != NULL) { + // See if the commitment can be shrunken after the pages are discarded. + const off_t areaCacheBase = area->Base() - area->cache_offset; + const off_t endAddress = address + size; + for (off_t pageAddress = address; pageAddress < endAddress; pageAddress += B_PAGE_SIZE) { + if (cache->LookupPage(pageAddress - areaCacheBase) == NULL) + continue; + + const bool isWritable + = (get_area_page_protection(area, pageAddress) & B_WRITE_AREA) != 0; + if (!isWritable) + commitmentChange -= B_PAGE_SIZE; + } + } + // Since VMCache::Discard() can temporarily drop the lock, we must // unlock all lower caches to prevent locking order inversion. cacheChainLocker.Unlock(cache); cache->Discard(cache->virtual_base + offset, size); - cache->ReleaseRefAndUnlock(); + if (commitmentChange != 0) + cache->Commit(cache->committed_size + commitmentChange, VM_PRIORITY_USER); + + cache->ReleaseRefAndUnlock(); return B_OK; }