* All mapped pages that are not wired (ie. locked) now have a vm_page_mapping object
that points to both, the page and the area the page is in. This will allow a page scanner to steal unused pages when necessary. * The locking is currently done with a spinlock which we might want to have another look at one day. * dump_page() and dump_area_struct() now dump the page mappings as well. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20356 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -62,6 +62,7 @@ status_t vm_create_vnode_cache(void *vnode, vm_cache_ref **_cacheRef);
|
|||||||
vm_area *vm_area_lookup(vm_address_space *addressSpace, addr_t address);
|
vm_area *vm_area_lookup(vm_address_space *addressSpace, addr_t address);
|
||||||
status_t vm_set_area_memory_type(area_id id, addr_t physicalBase, uint32 type);
|
status_t vm_set_area_memory_type(area_id id, addr_t physicalBase, uint32 type);
|
||||||
status_t vm_get_page_mapping(team_id team, addr_t vaddr, addr_t *paddr);
|
status_t vm_get_page_mapping(team_id team, addr_t vaddr, addr_t *paddr);
|
||||||
|
void vm_remove_all_page_mappings(vm_page *page);
|
||||||
status_t vm_unmap_pages(vm_area *area, addr_t base, size_t length);
|
status_t vm_unmap_pages(vm_area *area, addr_t base, size_t length);
|
||||||
status_t vm_map_page(vm_area *area, vm_page *page, addr_t address,
|
status_t vm_map_page(vm_area *area, vm_page *page, addr_t address,
|
||||||
uint32 protection);
|
uint32 protection);
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ class DoublyLinkedAreaLink {
|
|||||||
typedef class DoublyLinkedQueue<vm_page_mapping, DoublyLinkedPageLink> vm_page_mappings;
|
typedef class DoublyLinkedQueue<vm_page_mapping, DoublyLinkedPageLink> vm_page_mappings;
|
||||||
typedef class DoublyLinkedQueue<vm_page_mapping, DoublyLinkedAreaLink> vm_area_mappings;
|
typedef class DoublyLinkedQueue<vm_page_mapping, DoublyLinkedAreaLink> vm_area_mappings;
|
||||||
#else // !__cplusplus
|
#else // !__cplusplus
|
||||||
typedef void *vm_page_mappings;
|
typedef struct vm_page_mapping *vm_page_mappings;
|
||||||
typedef void *vm_area_mappings;
|
typedef struct vm_page_mapping *vm_area_mappings;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// vm page
|
// vm page
|
||||||
|
|||||||
+118
-7
@@ -64,6 +64,7 @@ extern vm_address_space *kernel_aspace;
|
|||||||
static area_id sNextAreaID;
|
static area_id sNextAreaID;
|
||||||
static hash_table *sAreaHash;
|
static hash_table *sAreaHash;
|
||||||
static sem_id sAreaHashLock;
|
static sem_id sAreaHashLock;
|
||||||
|
static spinlock sMappingLock;
|
||||||
|
|
||||||
static off_t sAvailableMemory;
|
static off_t sAvailableMemory;
|
||||||
static benaphore sAvailableMemoryLock;
|
static benaphore sAvailableMemoryLock;
|
||||||
@@ -170,6 +171,7 @@ create_area_struct(vm_address_space *addressSpace, const char *name,
|
|||||||
area->address_space_next = NULL;
|
area->address_space_next = NULL;
|
||||||
area->cache_next = area->cache_prev = NULL;
|
area->cache_next = area->cache_prev = NULL;
|
||||||
area->hash_next = NULL;
|
area->hash_next = NULL;
|
||||||
|
new (&area->mappings) vm_area_mappings;
|
||||||
|
|
||||||
return area;
|
return area;
|
||||||
}
|
}
|
||||||
@@ -1834,6 +1836,40 @@ vm_get_page_mapping(team_id aid, addr_t vaddr, addr_t *paddr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
vm_remove_all_page_mappings(vm_page *page)
|
||||||
|
{
|
||||||
|
cpu_status state = disable_interrupts();
|
||||||
|
acquire_spinlock(&sMappingLock);
|
||||||
|
|
||||||
|
vm_page_mappings queue;
|
||||||
|
queue.MoveFrom(&page->mappings);
|
||||||
|
|
||||||
|
vm_page_mappings::Iterator iterator = queue.GetIterator();
|
||||||
|
vm_page_mapping *mapping;
|
||||||
|
while ((mapping = iterator.Next()) != NULL) {
|
||||||
|
vm_area *area = mapping->area;
|
||||||
|
vm_translation_map *map = &area->address_space->translation_map;
|
||||||
|
|
||||||
|
map->ops->lock(map);
|
||||||
|
addr_t base = area->base + (page->cache_offset << PAGE_SHIFT);
|
||||||
|
map->ops->unmap(map, base, base + (B_PAGE_SIZE - 1));
|
||||||
|
map->ops->unlock(map);
|
||||||
|
|
||||||
|
area->mappings.Remove(mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
release_spinlock(&sMappingLock);
|
||||||
|
restore_interrupts(state);
|
||||||
|
|
||||||
|
// free now unused mappings
|
||||||
|
|
||||||
|
while ((mapping = queue.RemoveHead()) != NULL) {
|
||||||
|
free(mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
vm_unmap_pages(vm_area *area, addr_t base, size_t size)
|
vm_unmap_pages(vm_area *area, addr_t base, size_t size)
|
||||||
{
|
{
|
||||||
@@ -1864,6 +1900,37 @@ vm_unmap_pages(vm_area *area, addr_t base, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
map->ops->unmap(map, base, base + (size - 1));
|
map->ops->unmap(map, base, base + (size - 1));
|
||||||
|
|
||||||
|
if (area->wiring == B_NO_LOCK) {
|
||||||
|
vm_area_mappings queue;
|
||||||
|
uint32 count = 0;
|
||||||
|
|
||||||
|
cpu_status state = disable_interrupts();
|
||||||
|
acquire_spinlock(&sMappingLock);
|
||||||
|
|
||||||
|
vm_page_mapping *mapping;
|
||||||
|
while ((mapping = area->mappings.RemoveHead()) != NULL) {
|
||||||
|
mapping->page->mappings.Remove(mapping);
|
||||||
|
queue.Add(mapping);
|
||||||
|
|
||||||
|
// temporary unlock to handle interrupts and let others play as well
|
||||||
|
if ((++count % 256) == 0) {
|
||||||
|
release_spinlock(&sMappingLock);
|
||||||
|
restore_interrupts(state);
|
||||||
|
|
||||||
|
state = disable_interrupts();
|
||||||
|
acquire_spinlock(&sMappingLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
release_spinlock(&sMappingLock);
|
||||||
|
restore_interrupts(state);
|
||||||
|
|
||||||
|
while ((mapping = queue.RemoveHead()) != NULL) {
|
||||||
|
free(mapping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
map->ops->unlock(map);
|
map->ops->unlock(map);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -1873,17 +1940,38 @@ status_t
|
|||||||
vm_map_page(vm_area *area, vm_page *page, addr_t address, uint32 protection)
|
vm_map_page(vm_area *area, vm_page *page, addr_t address, uint32 protection)
|
||||||
{
|
{
|
||||||
vm_translation_map *map = &area->address_space->translation_map;
|
vm_translation_map *map = &area->address_space->translation_map;
|
||||||
|
vm_page_mapping *mapping = NULL;
|
||||||
|
|
||||||
|
if (area->wiring == B_NO_LOCK) {
|
||||||
|
mapping = (vm_page_mapping *)malloc(sizeof(vm_page_mapping));
|
||||||
|
if (mapping == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
mapping->page = page;
|
||||||
|
mapping->area = area;
|
||||||
|
}
|
||||||
|
|
||||||
map->ops->lock(map);
|
map->ops->lock(map);
|
||||||
map->ops->map(map, address, page->physical_page_number * B_PAGE_SIZE,
|
map->ops->map(map, address, page->physical_page_number * B_PAGE_SIZE,
|
||||||
protection);
|
protection);
|
||||||
map->ops->unlock(map);
|
|
||||||
|
|
||||||
if (area->wiring != B_NO_LOCK) {
|
if (area->wiring != B_NO_LOCK) {
|
||||||
page->wired_count++;
|
page->wired_count++;
|
||||||
// TODO: needs to be atomic on all platforms!
|
// TODO: needs to be atomic on all platforms!
|
||||||
|
} else {
|
||||||
|
// insert mapping into lists
|
||||||
|
cpu_status state = disable_interrupts();
|
||||||
|
acquire_spinlock(&sMappingLock);
|
||||||
|
|
||||||
|
page->mappings.Add(mapping);
|
||||||
|
area->mappings.Add(mapping);
|
||||||
|
|
||||||
|
release_spinlock(&sMappingLock);
|
||||||
|
restore_interrupts(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
map->ops->unlock(map);
|
||||||
|
|
||||||
vm_page_set_state(page, PAGE_STATE_ACTIVE);
|
vm_page_set_state(page, PAGE_STATE_ACTIVE);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -2211,7 +2299,7 @@ dump_cache(int argc, char **argv)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_dump_area(vm_area *area)
|
dump_area_struct(vm_area *area, bool mappings)
|
||||||
{
|
{
|
||||||
kprintf("AREA: %p\n", area);
|
kprintf("AREA: %p\n", area);
|
||||||
kprintf("name:\t\t'%s'\n", area->name);
|
kprintf("name:\t\t'%s'\n", area->name);
|
||||||
@@ -2228,39 +2316,62 @@ _dump_area(vm_area *area)
|
|||||||
kprintf("cache_offset:\t0x%Lx\n", area->cache_offset);
|
kprintf("cache_offset:\t0x%Lx\n", area->cache_offset);
|
||||||
kprintf("cache_next:\t%p\n", area->cache_next);
|
kprintf("cache_next:\t%p\n", area->cache_next);
|
||||||
kprintf("cache_prev:\t%p\n", area->cache_prev);
|
kprintf("cache_prev:\t%p\n", area->cache_prev);
|
||||||
|
|
||||||
|
vm_area_mappings::Iterator iterator = area->mappings.GetIterator();
|
||||||
|
if (mappings) {
|
||||||
|
kprintf("page mappings:\n");
|
||||||
|
while (iterator.HasNext()) {
|
||||||
|
vm_page_mapping *mapping = iterator.Next();
|
||||||
|
kprintf(" %p", mapping->page);
|
||||||
|
}
|
||||||
|
kprintf("\n");
|
||||||
|
} else {
|
||||||
|
uint32 count = 0;
|
||||||
|
while (iterator.Next() != NULL) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
kprintf("page mappings:\t%lu\n", count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dump_area(int argc, char **argv)
|
dump_area(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
bool mappings = false;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
int32 index = 1;
|
||||||
vm_area *area;
|
vm_area *area;
|
||||||
addr_t num;
|
addr_t num;
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
kprintf("usage: area <id|address|name>\n");
|
kprintf("usage: area [-m] <id|address|name>\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
num = strtoul(argv[1], NULL, 0);
|
if (!strcmp(argv[1], "-m")) {
|
||||||
|
mappings = true;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
num = strtoul(argv[index], NULL, 0);
|
||||||
|
|
||||||
// walk through the area list, looking for the arguments as a name
|
// walk through the area list, looking for the arguments as a name
|
||||||
struct hash_iterator iter;
|
struct hash_iterator iter;
|
||||||
|
|
||||||
hash_open(sAreaHash, &iter);
|
hash_open(sAreaHash, &iter);
|
||||||
while ((area = (vm_area *)hash_next(sAreaHash, &iter)) != NULL) {
|
while ((area = (vm_area *)hash_next(sAreaHash, &iter)) != NULL) {
|
||||||
if ((area->name != NULL && !strcmp(argv[1], area->name))
|
if ((area->name != NULL && !strcmp(argv[index], area->name))
|
||||||
|| num != 0
|
|| num != 0
|
||||||
&& ((addr_t)area->id == num
|
&& ((addr_t)area->id == num
|
||||||
|| area->base <= num && area->base + area->size > num)) {
|
|| area->base <= num && area->base + area->size > num)) {
|
||||||
_dump_area(area);
|
dump_area_struct(area, mappings);
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
kprintf("could not find area %s (%ld)\n", argv[1], num);
|
kprintf("could not find area %s (%ld)\n", argv[index], num);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ dump_free_page_table(int argc, char **argv)
|
|||||||
static int
|
static int
|
||||||
dump_page(int argc, char **argv)
|
dump_page(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
struct vm_page_mapping *mapping;
|
||||||
struct vm_page *page;
|
struct vm_page *page;
|
||||||
addr_t address;
|
addr_t address;
|
||||||
bool physical = false;
|
bool physical = false;
|
||||||
@@ -187,6 +188,13 @@ dump_page(int argc, char **argv)
|
|||||||
kprintf("state: %d\n", page->state);
|
kprintf("state: %d\n", page->state);
|
||||||
kprintf("wired_count: %u\n", page->wired_count);
|
kprintf("wired_count: %u\n", page->wired_count);
|
||||||
kprintf("usage_count: %u\n", page->usage_count);
|
kprintf("usage_count: %u\n", page->usage_count);
|
||||||
|
kprintf("area mappings:\n");
|
||||||
|
|
||||||
|
mapping = page->mappings;
|
||||||
|
while (mapping != NULL) {
|
||||||
|
kprintf(" %p\n", mapping->area);
|
||||||
|
mapping = mapping->page_link.next;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user