kernel/vm: Introduce methods to change the cache of all an area's clones.

This will be useful in the case of cloned device caches based
around physical memory, e.g. for framebuffers.

Change-Id: If2b864208e86f436e91379b73c4b866b0bd5e1d7
Reviewed-on: https://review.haiku-os.org/c/haiku/+/10558
Reviewed-by: waddlesplash <[email protected]>
Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
Augustin Cavalier
2026-03-24 14:01:11 +00:00
committed by waddlesplash
parent 861f644f19
commit 95ace7f374
2 changed files with 91 additions and 0 deletions
+1
View File
@@ -111,6 +111,7 @@ area_id vm_copy_area(team_id team, const char *name, void **_address,
area_id vm_clone_area(team_id team, const char *name, void **address, area_id vm_clone_area(team_id team, const char *name, void **address,
uint32 addressSpec, uint32 protection, uint32 mapping, uint32 addressSpec, uint32 protection, uint32 mapping,
area_id sourceArea, bool kernel); area_id sourceArea, bool kernel);
status_t vm_change_clones_to_null_areas(area_id area);
status_t vm_delete_area(team_id teamID, area_id areaID, bool kernel); status_t vm_delete_area(team_id teamID, area_id areaID, bool kernel);
status_t vm_create_vnode_cache(struct vnode *vnode, struct VMCache **_cache); status_t vm_create_vnode_cache(struct vnode *vnode, struct VMCache **_cache);
status_t vm_set_area_memory_type(area_id id, phys_addr_t physicalBase, status_t vm_set_area_memory_type(area_id id, phys_addr_t physicalBase,
+90
View File
@@ -2612,6 +2612,96 @@ vm_clone_area(team_id team, const char* name, void** address,
} }
/*! Changes all clones of an area (but not the area itself) to use a different cache
(and thus no longer be clones of this area.)
The target cache must be locked.
*/
status_t
vm_change_cache_of_clones(area_id areaId, struct VMCache* toCache)
{
AddressSpaceReadLocker addressSpaceLocker;
VMArea* fromArea;
addressSpaceLocker.SetFromArea(areaId, fromArea);
VMCache* cache = vm_area_get_locked_cache(fromArea);
addressSpaceLocker.Unlock();
VMCacheChainLocker cacheChainLocker(cache);
cacheChainLocker.LockAllSourceCaches();
VMArea* area = NULL;
int32 releaseStoreRefs = 0;
while (true) {
if (area == NULL)
area = cache->areas.First();
else
area = cache->areas.GetNext(area);
if (area == NULL)
break;
if (area == fromArea)
continue;
ASSERT(!area->IsWired());
unmap_pages(area, area->Base(), area->Size());
rw_lock_write_lock(&sAreaCacheLock);
// We have to do this manually, because RemoveArea() expects
// to be called unlocked, so it can call ReleaseStoreRef().
cache->areas.Remove(area);
area->cache = toCache;
area->cache_type = cache->type;
toCache->InsertAreaLocked(area);
toCache->AcquireRefLocked();
rw_lock_write_unlock(&sAreaCacheLock);
cache->ReleaseRefLocked();
releaseStoreRefs++;
// We removed this area, so restart iteration.
area = NULL;
}
// Release the store references after dropping the lock.
cacheChainLocker.Unlock(cache);
cache->Unlock();
while (releaseStoreRefs > 0) {
cache->ReleaseStoreRef();
releaseStoreRefs--;
}
// Release the reference kept when unlocking the chain.
cache->ReleaseRef();
return B_OK;
}
/*! Changes all clones of an area (but not the area itself) to be null areas.
*/
status_t
vm_change_clones_to_null_areas(area_id areaId)
{
VMCache* cache;
status_t status = VMCacheFactory::CreateNullCache(VM_PRIORITY_SYSTEM, cache);
if (status != B_OK)
return status;
cache->Lock();
cache->temporary = 1;
cache->virtual_end = SSIZE_MAX;
status = vm_change_cache_of_clones(areaId, cache);
cache->ReleaseRefAndUnlock();
return status;
}
/*! Deletes the specified area of the given address space. /*! Deletes the specified area of the given address space.
The address space must be write-locked. The address space must be write-locked.