kernel/vm: Areas without source caches need commitments for READ protections.
May fix #19678.
This commit is contained in:
+32
-24
@@ -594,11 +594,15 @@ get_area_page_protection(VMArea* area, addr_t pageAddress)
|
|||||||
/*! Computes the committed size an area's cache ought to have,
|
/*! Computes the committed size an area's cache ought to have,
|
||||||
based on the area's page_protections and any pages already present.
|
based on the area's page_protections and any pages already present.
|
||||||
*/
|
*/
|
||||||
static inline uint32
|
static inline size_t
|
||||||
compute_area_page_commitment(VMArea* area)
|
compute_area_page_commitment(VMArea* area)
|
||||||
{
|
{
|
||||||
|
uint32 commitProtection = B_WRITE_AREA | B_KERNEL_WRITE_AREA;
|
||||||
|
if (area->cache->source == NULL)
|
||||||
|
commitProtection |= B_READ_AREA | B_KERNEL_READ_AREA;
|
||||||
|
|
||||||
if (area->page_protections == NULL) {
|
if (area->page_protections == NULL) {
|
||||||
if ((area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0)
|
if ((area->protection & commitProtection) != 0)
|
||||||
return area->Size();
|
return area->Size();
|
||||||
return area->cache->page_count * B_PAGE_SIZE;
|
return area->cache->page_count * B_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
@@ -612,7 +616,7 @@ compute_area_page_commitment(VMArea* area)
|
|||||||
if (area->cache->LookupPage(pageOffset) != NULL)
|
if (area->cache->LookupPage(pageOffset) != NULL)
|
||||||
pages++;
|
pages++;
|
||||||
else
|
else
|
||||||
pages += ((protection & (B_WRITE_AREA << 0)) != 0) ? 1 : 0;
|
pages += ((protection & (commitProtection << 0)) != 0) ? 1 : 0;
|
||||||
|
|
||||||
if (i == (bytes - 1) && oddPageCount)
|
if (i == (bytes - 1) && oddPageCount)
|
||||||
break;
|
break;
|
||||||
@@ -620,7 +624,7 @@ compute_area_page_commitment(VMArea* area)
|
|||||||
if (area->cache->LookupPage(pageOffset + B_PAGE_SIZE) != NULL)
|
if (area->cache->LookupPage(pageOffset + B_PAGE_SIZE) != NULL)
|
||||||
pages++;
|
pages++;
|
||||||
else
|
else
|
||||||
pages += ((protection & (B_WRITE_AREA << 4)) != 0) ? 1 : 0;
|
pages += ((protection & (commitProtection << 4)) != 0) ? 1 : 0;
|
||||||
}
|
}
|
||||||
return pages;
|
return pages;
|
||||||
}
|
}
|
||||||
@@ -1260,8 +1264,16 @@ map_backing_store(VMAddressSpace* addressSpace, VMCache* cache, off_t offset,
|
|||||||
cache = newCache;
|
cache = newCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// attach the cache to the area
|
||||||
|
area->cache = cache;
|
||||||
|
area->cache_offset = offset;
|
||||||
|
|
||||||
|
// point the cache back to the area
|
||||||
|
cache->InsertAreaLocked(area);
|
||||||
|
|
||||||
if ((flags & CREATE_AREA_DONT_COMMIT_MEMORY) == 0) {
|
if ((flags & CREATE_AREA_DONT_COMMIT_MEMORY) == 0) {
|
||||||
status = cache->SetMinimalCommitment(size, priority);
|
const size_t commitmentPages = compute_area_page_commitment(area);
|
||||||
|
status = cache->SetMinimalCommitment(commitmentPages * B_PAGE_SIZE, priority);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
goto err2;
|
goto err2;
|
||||||
}
|
}
|
||||||
@@ -1298,12 +1310,6 @@ map_backing_store(VMAddressSpace* addressSpace, VMCache* cache, off_t offset,
|
|||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
goto err2;
|
goto err2;
|
||||||
|
|
||||||
// attach the cache to the area
|
|
||||||
area->cache = cache;
|
|
||||||
area->cache_offset = offset;
|
|
||||||
|
|
||||||
// point the cache back to the area
|
|
||||||
cache->InsertAreaLocked(area);
|
|
||||||
if (mapping == REGION_PRIVATE_MAP)
|
if (mapping == REGION_PRIVATE_MAP)
|
||||||
cache->Unlock();
|
cache->Unlock();
|
||||||
|
|
||||||
@@ -1323,9 +1329,13 @@ map_backing_store(VMAddressSpace* addressSpace, VMCache* cache, off_t offset,
|
|||||||
|
|
||||||
err3:
|
err3:
|
||||||
cache->Lock();
|
cache->Lock();
|
||||||
cache->RemoveArea(area);
|
addressSpace->RemoveArea(area, allocationFlags);
|
||||||
area->cache = NULL;
|
|
||||||
err2:
|
err2:
|
||||||
|
cache->Unlock();
|
||||||
|
cache->RemoveArea(area);
|
||||||
|
cache->Lock();
|
||||||
|
area->cache = NULL;
|
||||||
|
|
||||||
if (mapping == REGION_PRIVATE_MAP) {
|
if (mapping == REGION_PRIVATE_MAP) {
|
||||||
// We created this cache, so we must delete it again. Note, that we
|
// We created this cache, so we must delete it again. Note, that we
|
||||||
// need to temporarily unlock the source cache or we'll otherwise
|
// need to temporarily unlock the source cache or we'll otherwise
|
||||||
@@ -2313,12 +2323,6 @@ _vm_map_file(team_id team, const char* name, void** _address,
|
|||||||
uint32 mappingFlags = 0;
|
uint32 mappingFlags = 0;
|
||||||
if (unmapAddressRange)
|
if (unmapAddressRange)
|
||||||
mappingFlags |= CREATE_AREA_UNMAP_ADDRESS_RANGE;
|
mappingFlags |= CREATE_AREA_UNMAP_ADDRESS_RANGE;
|
||||||
if (mapping == REGION_PRIVATE_MAP) {
|
|
||||||
// For privately mapped read-only regions, skip committing memory.
|
|
||||||
// (If protections are changed later on, memory will be committed then.)
|
|
||||||
if ((protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) == 0)
|
|
||||||
mappingFlags |= CREATE_AREA_DONT_COMMIT_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
virtual_address_restrictions virtualRestrictions = {};
|
virtual_address_restrictions virtualRestrictions = {};
|
||||||
@@ -6430,7 +6434,11 @@ _user_set_memory_protection(void* _address, size_t size, uint32 protection)
|
|||||||
|
|
||||||
// Adjust the committed size, if necessary.
|
// Adjust the committed size, if necessary.
|
||||||
if (is_area_only_cache_user(area) && !topCache->CanOvercommit()) {
|
if (is_area_only_cache_user(area) && !topCache->CanOvercommit()) {
|
||||||
const bool becomesWritable = (protection & B_WRITE_AREA) != 0;
|
uint8 commitProtection = B_WRITE_AREA;
|
||||||
|
if (topCache->source == NULL)
|
||||||
|
commitProtection |= B_READ_AREA;
|
||||||
|
const bool newNeedsCommitment = (protection & commitProtection) != 0;
|
||||||
|
|
||||||
ssize_t commitmentChange = 0;
|
ssize_t commitmentChange = 0;
|
||||||
const off_t areaCacheBase = area->Base() - area->cache_offset;
|
const off_t areaCacheBase = area->Base() - area->cache_offset;
|
||||||
for (addr_t pageAddress = area->Base() + offset;
|
for (addr_t pageAddress = area->Base() + offset;
|
||||||
@@ -6440,12 +6448,12 @@ _user_set_memory_protection(void* _address, size_t size, uint32 protection)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool isWritable
|
const bool nowNeedsCommitment
|
||||||
= (get_area_page_protection(area, pageAddress) & B_WRITE_AREA) != 0;
|
= (get_area_page_protection(area, pageAddress) & commitProtection) != 0;
|
||||||
|
|
||||||
if (becomesWritable && !isWritable)
|
if (newNeedsCommitment && !nowNeedsCommitment)
|
||||||
commitmentChange += B_PAGE_SIZE;
|
commitmentChange += B_PAGE_SIZE;
|
||||||
else if (!becomesWritable && isWritable)
|
else if (!newNeedsCommitment && nowNeedsCommitment)
|
||||||
commitmentChange -= B_PAGE_SIZE;
|
commitmentChange -= B_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user