First go at set_area_protection() - does work for everything but changing
a read-only area to read/write. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10213 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+104
-3
@@ -1349,6 +1349,108 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
vm_set_area_protection(aspace_id aspaceID, area_id areaID, uint32 newProtection)
|
||||||
|
{
|
||||||
|
vm_cache_ref *cacheRef;
|
||||||
|
vm_cache *cache;
|
||||||
|
vm_area *area;
|
||||||
|
status_t status = B_OK;
|
||||||
|
|
||||||
|
TRACE(("vm_set_area_protection(aspace = %#lx, area = %#lx, protection = %#lx)\n",
|
||||||
|
aspaceID, areaID, newProtection));
|
||||||
|
|
||||||
|
if ((newProtection & (B_EXECUTE_AREA | B_KERNEL_EXECUTE_AREA)) != 0
|
||||||
|
&& (newProtection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0) {
|
||||||
|
// executable areas must not be writable
|
||||||
|
return B_NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
area = vm_get_area(areaID);
|
||||||
|
if (area == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (aspaceID != vm_get_kernel_aspace_id() && area->aspace->id != aspaceID) {
|
||||||
|
// unless you're the kernel, you are only allowed to set
|
||||||
|
// the protection of your own areas
|
||||||
|
vm_put_area(area);
|
||||||
|
return B_NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheRef = area->cache_ref;
|
||||||
|
cache = cacheRef->cache;
|
||||||
|
|
||||||
|
mutex_lock(&cacheRef->lock);
|
||||||
|
|
||||||
|
if ((area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0
|
||||||
|
&& (newProtection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) == 0) {
|
||||||
|
// change from read/write to read-only
|
||||||
|
|
||||||
|
if (cache->source != NULL && cache->temporary) {
|
||||||
|
uint32 writableAreas = 0;
|
||||||
|
struct vm_area *cacheArea = cacheRef->areas;
|
||||||
|
for (; cacheArea != NULL; cacheArea = cacheArea->cache_next) {
|
||||||
|
if (cacheArea != area
|
||||||
|
&& (cacheArea->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0)
|
||||||
|
writableAreas++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writableAreas == 0) {
|
||||||
|
// Since this cache now lives from the pages in its source cache,
|
||||||
|
// we can change the cache's commitment to take only those pages
|
||||||
|
// into account that really are in this cache.
|
||||||
|
|
||||||
|
// count existing pages in this cache
|
||||||
|
struct vm_page *page = cache->page_list;
|
||||||
|
uint32 count = 0;
|
||||||
|
|
||||||
|
for (; page != NULL; page = page->cache_next) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = cache->store->ops->commit(cache->store, count * B_PAGE_SIZE);
|
||||||
|
|
||||||
|
// ToDo: we may be able to join with our source cache, if any
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((area->protection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) == 0
|
||||||
|
&& (newProtection & (B_WRITE_AREA | B_KERNEL_WRITE_AREA)) != 0) {
|
||||||
|
// change from read-only to read/write
|
||||||
|
|
||||||
|
// ToDo: if this is a shared cache, insert new cache
|
||||||
|
// ToDo: eventually change commitment
|
||||||
|
status = B_ERROR;
|
||||||
|
} else {
|
||||||
|
// we don't have anything special to do in all other cases
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == B_OK && area->protection != newProtection) {
|
||||||
|
// remap existing pages in this cache
|
||||||
|
struct vm_translation_map *map = &area->aspace->translation_map;
|
||||||
|
struct vm_page *page = cache->page_list;
|
||||||
|
|
||||||
|
map->ops->lock(map);
|
||||||
|
|
||||||
|
for (; page != NULL; page = page->cache_next) {
|
||||||
|
// only map those pages inside the area
|
||||||
|
if (page->offset >= area->cache_offset
|
||||||
|
&& page->offset < area->cache_offset + area->size) {
|
||||||
|
map->ops->map(map, area->base + page->offset - area->cache_offset,
|
||||||
|
page->ppn * B_PAGE_SIZE, newProtection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map->ops->unlock(map);
|
||||||
|
area->protection = newProtection;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&cacheRef->lock);
|
||||||
|
vm_put_area(area);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
vm_get_page_mapping(aspace_id aid, addr_t vaddr, addr_t *paddr)
|
vm_get_page_mapping(aspace_id aid, addr_t vaddr, addr_t *paddr)
|
||||||
{
|
{
|
||||||
@@ -2679,8 +2781,7 @@ _get_next_area_info(team_id team, int32 *cookie, area_info *info, size_t size)
|
|||||||
status_t
|
status_t
|
||||||
set_area_protection(area_id area, uint32 newProtection)
|
set_area_protection(area_id area, uint32 newProtection)
|
||||||
{
|
{
|
||||||
// ToDo: implement set_area_protection()
|
return vm_set_area_protection(vm_get_kernel_aspace_id(), area, newProtection);
|
||||||
return B_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2891,7 +2992,7 @@ _user_set_area_protection(area_id area, uint32 newProtection)
|
|||||||
if ((newProtection & ~B_USER_PROTECTION) != 0)
|
if ((newProtection & ~B_USER_PROTECTION) != 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
return set_area_protection(area, newProtection);
|
return vm_set_area_protection(vm_get_current_user_aspace_id(), area, newProtection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user