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:
committed by
waddlesplash
parent
861f644f19
commit
95ace7f374
@@ -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,
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user