* 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:
parent
1d4134cb51
commit
1594e83f84
|
@ -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);
|
||||
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);
|
||||
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_map_page(vm_area *area, vm_page *page, addr_t address,
|
||||
uint32 protection);
|
||||
|
|
|
@ -61,8 +61,8 @@ class DoublyLinkedAreaLink {
|
|||
typedef class DoublyLinkedQueue<vm_page_mapping, DoublyLinkedPageLink> vm_page_mappings;
|
||||
typedef class DoublyLinkedQueue<vm_page_mapping, DoublyLinkedAreaLink> vm_area_mappings;
|
||||
#else // !__cplusplus
|
||||
typedef void *vm_page_mappings;
|
||||
typedef void *vm_area_mappings;
|
||||
typedef struct vm_page_mapping *vm_page_mappings;
|
||||
typedef struct vm_page_mapping *vm_area_mappings;
|
||||
#endif
|
||||
|
||||
// vm page
|
||||
|
|
|
@ -64,6 +64,7 @@ extern vm_address_space *kernel_aspace;
|
|||
static area_id sNextAreaID;
|
||||
static hash_table *sAreaHash;
|
||||
static sem_id sAreaHashLock;
|
||||
static spinlock sMappingLock;
|
||||
|
||||
static off_t sAvailableMemory;
|
||||
static benaphore sAvailableMemoryLock;
|
||||
|
@ -170,6 +171,7 @@ create_area_struct(vm_address_space *addressSpace, const char *name,
|
|||
area->address_space_next = NULL;
|
||||
area->cache_next = area->cache_prev = NULL;
|
||||
area->hash_next = NULL;
|
||||
new (&area->mappings) vm_area_mappings;
|
||||
|
||||
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
|
||||
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));
|
||||
|
||||
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);
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -1873,17 +1940,38 @@ status_t
|
|||
vm_map_page(vm_area *area, vm_page *page, addr_t address, uint32 protection)
|
||||
{
|
||||
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->map(map, address, page->physical_page_number * B_PAGE_SIZE,
|
||||
protection);
|
||||
map->ops->unlock(map);
|
||||
|
||||
if (area->wiring != B_NO_LOCK) {
|
||||
page->wired_count++;
|
||||
// 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);
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -2211,7 +2299,7 @@ dump_cache(int argc, char **argv)
|
|||
|
||||
|
||||
static void
|
||||
_dump_area(vm_area *area)
|
||||
dump_area_struct(vm_area *area, bool mappings)
|
||||
{
|
||||
kprintf("AREA: %p\n", area);
|
||||
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_next:\t%p\n", area->cache_next);
|
||||
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
|
||||
dump_area(int argc, char **argv)
|
||||
{
|
||||
bool mappings = false;
|
||||
bool found = false;
|
||||
int32 index = 1;
|
||||
vm_area *area;
|
||||
addr_t num;
|
||||
|
||||
if (argc < 2) {
|
||||
kprintf("usage: area <id|address|name>\n");
|
||||
kprintf("usage: area [-m] <id|address|name>\n");
|
||||
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
|
||||
struct hash_iterator iter;
|
||||
|
||||
hash_open(sAreaHash, &iter);
|
||||
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
|
||||
&& ((addr_t)area->id == num
|
||||
|| area->base <= num && area->base + area->size > num)) {
|
||||
_dump_area(area);
|
||||
dump_area_struct(area, mappings);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -136,6 +136,7 @@ dump_free_page_table(int argc, char **argv)
|
|||
static int
|
||||
dump_page(int argc, char **argv)
|
||||
{
|
||||
struct vm_page_mapping *mapping;
|
||||
struct vm_page *page;
|
||||
addr_t address;
|
||||
bool physical = false;
|
||||
|
@ -187,6 +188,13 @@ dump_page(int argc, char **argv)
|
|||
kprintf("state: %d\n", page->state);
|
||||
kprintf("wired_count: %u\n", page->wired_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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue