* 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:
Axel Dörfler
2007-03-08 14:35:26 +00:00
parent 1d4134cb51
commit 1594e83f84
4 changed files with 129 additions and 9 deletions
+1
View File
@@ -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);
+2 -2
View File
@@ -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
View File
@@ -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;
} }
+8
View File
@@ -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;
} }