* Applied codestyle patch by Vasilis Kaoutsis (missing space between if/for and the
opening bracket) - thanks! * Shuffled functions a bit around to separate static and exported functions. * Some other cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20245 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
3eca858515
commit
583ed1c698
@ -56,14 +56,6 @@ static spinlock sPageLock;
|
||||
|
||||
static sem_id modified_pages_available;
|
||||
|
||||
static int dump_page(int argc, char **argv);
|
||||
static int dump_page_queue(int argc, char **argv);
|
||||
static int dump_page_stats(int argc, char **argv);
|
||||
static int dump_free_page_table(int argc, char **argv);
|
||||
static status_t vm_page_set_state_nolock(vm_page *page, int page_state);
|
||||
static void clear_page(addr_t pa);
|
||||
static int32 page_scrubber(void *);
|
||||
|
||||
|
||||
/*! Dequeues a page from the tail of the given queue */
|
||||
static vm_page *
|
||||
@ -107,32 +99,427 @@ enqueue_page(page_queue *q, vm_page *page)
|
||||
|
||||
|
||||
static void
|
||||
remove_page_from_queue(page_queue *q, vm_page *page)
|
||||
remove_page_from_queue(page_queue *queue, vm_page *page)
|
||||
{
|
||||
if (page->queue_prev != NULL)
|
||||
page->queue_prev->queue_next = page->queue_next;
|
||||
else
|
||||
q->head = page->queue_next;
|
||||
queue->head = page->queue_next;
|
||||
|
||||
if (page->queue_next != NULL)
|
||||
page->queue_next->queue_prev = page->queue_prev;
|
||||
else
|
||||
q->tail = page->queue_prev;
|
||||
queue->tail = page->queue_prev;
|
||||
|
||||
q->count--;
|
||||
queue->count--;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
move_page_to_queue(page_queue *from_q, page_queue *to_q, vm_page *page)
|
||||
move_page_to_queue(page_queue *fromQueue, page_queue *toQueue, vm_page *page)
|
||||
{
|
||||
if (from_q != to_q) {
|
||||
remove_page_from_queue(from_q, page);
|
||||
enqueue_page(to_q, page);
|
||||
if (fromQueue != toQueue) {
|
||||
remove_page_from_queue(fromQueue, page);
|
||||
enqueue_page(toQueue, page);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_free_page_table(int argc, char **argv)
|
||||
{
|
||||
dprintf("not finished\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_page(int argc, char **argv)
|
||||
{
|
||||
struct vm_page *page;
|
||||
addr_t address;
|
||||
bool physical = false;
|
||||
int32 index = 1;
|
||||
|
||||
if (argc > 2) {
|
||||
if (!strcmp(argv[1], "-p")) {
|
||||
physical = true;
|
||||
index++;
|
||||
} else if (!strcmp(argv[1], "-v"))
|
||||
index++;
|
||||
}
|
||||
|
||||
if (argc < 2
|
||||
|| strlen(argv[index]) <= 2
|
||||
|| argv[index][0] != '0'
|
||||
|| argv[index][1] != 'x') {
|
||||
kprintf("usage: page [-p|-v] <address>\n"
|
||||
" -v looks up a virtual address for the page, -p a physical address.\n"
|
||||
" Default is to look for the page structure address directly\n.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
address = strtoul(argv[index], NULL, 0);
|
||||
|
||||
if (index == 2) {
|
||||
if (!physical) {
|
||||
vm_address_space *addressSpace = vm_kernel_address_space();
|
||||
if (thread_get_current_thread()->team->address_space != NULL)
|
||||
addressSpace = thread_get_current_thread()->team->address_space;
|
||||
|
||||
addressSpace->translation_map.ops->query_interrupt(
|
||||
&addressSpace->translation_map, address, &address);
|
||||
|
||||
}
|
||||
page = vm_lookup_page(address / B_PAGE_SIZE);
|
||||
} else
|
||||
page = (struct vm_page *)address;
|
||||
|
||||
kprintf("PAGE: %p\n", page);
|
||||
kprintf("queue_next,prev: %p, %p\n", page->queue_next, page->queue_prev);
|
||||
kprintf("hash_next: %p\n", page->hash_next);
|
||||
kprintf("physical_number: %lx\n", page->physical_page_number);
|
||||
kprintf("cache: %p\n", page->cache);
|
||||
kprintf("cache_offset: %ld\n", page->cache_offset);
|
||||
kprintf("cache_next,prev: %p, %p\n", page->cache_next, page->cache_prev);
|
||||
kprintf("ref_count: %ld\n", page->ref_count);
|
||||
kprintf("type: %d\n", page->type);
|
||||
kprintf("state: %d\n", page->state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_page_queue(int argc, char **argv)
|
||||
{
|
||||
struct page_queue *queue;
|
||||
|
||||
if (argc < 2) {
|
||||
kprintf("usage: page_queue <address/name> [list]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strlen(argv[1]) >= 2 && argv[1][0] == '0' && argv[1][1] == 'x')
|
||||
queue = (struct page_queue *)strtoul(argv[1], NULL, 16);
|
||||
if (!strcmp(argv[1], "free"))
|
||||
queue = &page_free_queue;
|
||||
else if (!strcmp(argv[1], "clear"))
|
||||
queue = &page_clear_queue;
|
||||
else if (!strcmp(argv[1], "modified"))
|
||||
queue = &page_modified_queue;
|
||||
else if (!strcmp(argv[1], "active"))
|
||||
queue = &page_active_queue;
|
||||
else {
|
||||
kprintf("page_queue: unknown queue \"%s\".\n", argv[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kprintf("queue->head = %p, queue->tail = %p, queue->count = %d\n", queue->head, queue->tail, queue->count);
|
||||
|
||||
if (argc == 3) {
|
||||
struct vm_page *page = queue->head;
|
||||
int i;
|
||||
|
||||
for (i = 0; page; i++, page = page->queue_next) {
|
||||
kprintf("%5d. queue_next = %p, queue_prev = %p, type = %d, state = %d\n", i, page->queue_next, page->queue_prev, page->type, page->state);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_page_stats(int argc, char **argv)
|
||||
{
|
||||
uint32 counter[8];
|
||||
int32 totalActive;
|
||||
addr_t i;
|
||||
|
||||
memset(counter, 0, sizeof(counter));
|
||||
|
||||
for (i = 0; i < sNumPages; i++) {
|
||||
if (sPages[i].state > 7)
|
||||
panic("page %li at %p has invalid state!\n", i, &sPages[i]);
|
||||
|
||||
counter[sPages[i].state]++;
|
||||
}
|
||||
|
||||
kprintf("page stats:\n");
|
||||
kprintf("active: %lu\ninactive: %lu\nbusy: %lu\nunused: %lu\n",
|
||||
counter[PAGE_STATE_ACTIVE], counter[PAGE_STATE_INACTIVE], counter[PAGE_STATE_BUSY], counter[PAGE_STATE_UNUSED]);
|
||||
kprintf("wired: %lu\nmodified: %lu\nfree: %lu\nclear: %lu\n",
|
||||
counter[PAGE_STATE_WIRED], counter[PAGE_STATE_MODIFIED], counter[PAGE_STATE_FREE], counter[PAGE_STATE_CLEAR]);
|
||||
|
||||
kprintf("\nfree_queue: %p, count = %d\n", &page_free_queue, page_free_queue.count);
|
||||
kprintf("clear_queue: %p, count = %d\n", &page_clear_queue, page_clear_queue.count);
|
||||
kprintf("modified_queue: %p, count = %d\n", &page_modified_queue, page_modified_queue.count);
|
||||
kprintf("active_queue: %p, count = %d\n", &page_active_queue, page_active_queue.count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static int dump_free_page_table(int argc, char **argv)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
unsigned int free_start = END_OF_LIST;
|
||||
unsigned int inuse_start = PAGE_INUSE;
|
||||
|
||||
dprintf("dump_free_page_table():\n");
|
||||
dprintf("first_free_page_index = %d\n", first_free_page_index);
|
||||
|
||||
while(i < free_page_table_size) {
|
||||
if (free_page_table[i] == PAGE_INUSE) {
|
||||
if (inuse_start != PAGE_INUSE) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (free_start != END_OF_LIST) {
|
||||
dprintf("free from %d -> %d\n", free_start + free_page_table_base, i-1 + free_page_table_base);
|
||||
free_start = END_OF_LIST;
|
||||
}
|
||||
inuse_start = i;
|
||||
} else {
|
||||
if (free_start != END_OF_LIST) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (inuse_start != PAGE_INUSE) {
|
||||
dprintf("inuse from %d -> %d\n", inuse_start + free_page_table_base, i-1 + free_page_table_base);
|
||||
inuse_start = PAGE_INUSE;
|
||||
}
|
||||
free_start = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (inuse_start != PAGE_INUSE) {
|
||||
dprintf("inuse from %d -> %d\n", inuse_start + free_page_table_base, i-1 + free_page_table_base);
|
||||
}
|
||||
if (free_start != END_OF_LIST) {
|
||||
dprintf("free from %d -> %d\n", free_start + free_page_table_base, i-1 + free_page_table_base);
|
||||
}
|
||||
/*
|
||||
for (i = 0; i < free_page_table_size; i++) {
|
||||
dprintf("%d->%d ", i, free_page_table[i]);
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static status_t
|
||||
set_page_state_nolock(vm_page *page, int pageState)
|
||||
{
|
||||
page_queue *from_q = NULL;
|
||||
page_queue *to_q = NULL;
|
||||
|
||||
switch (page->state) {
|
||||
case PAGE_STATE_BUSY:
|
||||
case PAGE_STATE_ACTIVE:
|
||||
case PAGE_STATE_INACTIVE:
|
||||
case PAGE_STATE_WIRED:
|
||||
case PAGE_STATE_UNUSED:
|
||||
from_q = &page_active_queue;
|
||||
break;
|
||||
case PAGE_STATE_MODIFIED:
|
||||
from_q = &page_modified_queue;
|
||||
break;
|
||||
case PAGE_STATE_FREE:
|
||||
from_q = &page_free_queue;
|
||||
break;
|
||||
case PAGE_STATE_CLEAR:
|
||||
from_q = &page_clear_queue;
|
||||
break;
|
||||
default:
|
||||
panic("vm_page_set_state: vm_page %p in invalid state %d\n", page, page->state);
|
||||
}
|
||||
|
||||
switch (pageState) {
|
||||
case PAGE_STATE_BUSY:
|
||||
case PAGE_STATE_ACTIVE:
|
||||
case PAGE_STATE_INACTIVE:
|
||||
case PAGE_STATE_WIRED:
|
||||
case PAGE_STATE_UNUSED:
|
||||
to_q = &page_active_queue;
|
||||
break;
|
||||
case PAGE_STATE_MODIFIED:
|
||||
to_q = &page_modified_queue;
|
||||
break;
|
||||
case PAGE_STATE_FREE:
|
||||
to_q = &page_free_queue;
|
||||
break;
|
||||
case PAGE_STATE_CLEAR:
|
||||
to_q = &page_clear_queue;
|
||||
break;
|
||||
default:
|
||||
panic("vm_page_set_state: invalid target state %d\n", pageState);
|
||||
}
|
||||
page->state = pageState;
|
||||
move_page_to_queue(from_q, to_q, page);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
clear_page(addr_t pa)
|
||||
{
|
||||
addr_t va;
|
||||
|
||||
// dprintf("clear_page: clearing page 0x%x\n", pa);
|
||||
|
||||
vm_get_physical_page(pa, &va, PHYSICAL_PAGE_CAN_WAIT);
|
||||
|
||||
memset((void *)va, 0, B_PAGE_SIZE);
|
||||
|
||||
vm_put_physical_page(va);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
This is a background thread that wakes up every now and then (every 100ms)
|
||||
and moves some pages from the free queue over to the clear queue.
|
||||
Given enough time, it will clear out all pages from the free queue - we
|
||||
could probably slow it down after having reached a certain threshold.
|
||||
*/
|
||||
static int32
|
||||
page_scrubber(void *unused)
|
||||
{
|
||||
(void)(unused);
|
||||
|
||||
TRACE(("page_scrubber starting...\n"));
|
||||
|
||||
for (;;) {
|
||||
snooze(100000); // 100ms
|
||||
|
||||
if (page_free_queue.count > 0) {
|
||||
cpu_status state;
|
||||
vm_page *page[SCRUB_SIZE];
|
||||
int32 i, scrubCount;
|
||||
|
||||
// get some pages from the free queue
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
|
||||
for (i = 0; i < SCRUB_SIZE; i++) {
|
||||
page[i] = dequeue_page(&page_free_queue);
|
||||
if (page[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
|
||||
// clear them
|
||||
|
||||
scrubCount = i;
|
||||
|
||||
for (i = 0; i < scrubCount; i++) {
|
||||
clear_page(page[i]->physical_page_number * B_PAGE_SIZE);
|
||||
}
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
|
||||
// and put them into the clear queue
|
||||
|
||||
for (i = 0; i < scrubCount; i++) {
|
||||
page[i]->state = PAGE_STATE_CLEAR;
|
||||
enqueue_page(&page_clear_queue, page[i]);
|
||||
}
|
||||
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static int pageout_daemon()
|
||||
{
|
||||
int state;
|
||||
vm_page *page;
|
||||
vm_region *region;
|
||||
IOVECS(vecs, 1);
|
||||
ssize_t err;
|
||||
|
||||
dprintf("pageout daemon starting\n");
|
||||
|
||||
for (;;) {
|
||||
acquire_sem(modified_pages_available);
|
||||
|
||||
dprintf("here\n");
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
page = dequeue_page(&page_modified_queue);
|
||||
page->state = PAGE_STATE_BUSY;
|
||||
vm_cache_acquire_ref(page->cache_ref, true);
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
|
||||
dprintf("got page %p\n", page);
|
||||
|
||||
if (page->cache_ref->cache->temporary && !trimming_cycle) {
|
||||
// unless we're in the trimming cycle, dont write out pages
|
||||
// that back anonymous stores
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
enqueue_page(&page_modified_queue, page);
|
||||
page->state = PAGE_STATE_MODIFIED;
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
vm_cache_release_ref(page->cache_ref);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* clear the modified flag on this page in all it's mappings */
|
||||
mutex_lock(&page->cache_ref->lock);
|
||||
for (region = page->cache_ref->region_list; region; region = region->cache_next) {
|
||||
if (page->offset > region->cache_offset
|
||||
&& page->offset < region->cache_offset + region->size) {
|
||||
vm_translation_map *map = ®ion->aspace->translation_map;
|
||||
map->ops->lock(map);
|
||||
map->ops->clear_flags(map, page->offset - region->cache_offset + region->base, PAGE_MODIFIED);
|
||||
map->ops->unlock(map);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&page->cache_ref->lock);
|
||||
|
||||
/* write the page out to it's backing store */
|
||||
vecs->num = 1;
|
||||
vecs->total_len = PAGE_SIZE;
|
||||
vm_get_physical_page(page->physical_page_number * PAGE_SIZE, (addr_t *)&vecs->vec[0].iov_base, PHYSICAL_PAGE_CAN_WAIT);
|
||||
vecs->vec[0].iov_len = PAGE_SIZE;
|
||||
|
||||
err = page->cache_ref->cache->store->ops->write(page->cache_ref->cache->store, page->offset, vecs);
|
||||
|
||||
vm_put_physical_page((addr_t)vecs->vec[0].iov_base);
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
if (page->ref_count > 0) {
|
||||
page->state = PAGE_STATE_ACTIVE;
|
||||
} else {
|
||||
page->state = PAGE_STATE_INACTIVE;
|
||||
}
|
||||
enqueue_page(&page_active_queue, page);
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
|
||||
vm_cache_release_ref(page->cache_ref);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static status_t
|
||||
write_page(vm_page *page, bool fsReenter)
|
||||
{
|
||||
@ -163,6 +550,9 @@ write_page(vm_page *page, bool fsReenter)
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - private kernel API
|
||||
|
||||
|
||||
/*!
|
||||
You need to hold the vm_cache lock when calling this function.
|
||||
*/
|
||||
@ -267,85 +657,6 @@ vm_page_write_modified(vm_cache *cache, bool fsReenter)
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static int pageout_daemon()
|
||||
{
|
||||
int state;
|
||||
vm_page *page;
|
||||
vm_region *region;
|
||||
IOVECS(vecs, 1);
|
||||
ssize_t err;
|
||||
|
||||
dprintf("pageout daemon starting\n");
|
||||
|
||||
for (;;) {
|
||||
acquire_sem(modified_pages_available);
|
||||
|
||||
dprintf("here\n");
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
page = dequeue_page(&page_modified_queue);
|
||||
page->state = PAGE_STATE_BUSY;
|
||||
vm_cache_acquire_ref(page->cache_ref, true);
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
|
||||
dprintf("got page %p\n", page);
|
||||
|
||||
if(page->cache_ref->cache->temporary && !trimming_cycle) {
|
||||
// unless we're in the trimming cycle, dont write out pages
|
||||
// that back anonymous stores
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
enqueue_page(&page_modified_queue, page);
|
||||
page->state = PAGE_STATE_MODIFIED;
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
vm_cache_release_ref(page->cache_ref);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* clear the modified flag on this page in all it's mappings */
|
||||
mutex_lock(&page->cache_ref->lock);
|
||||
for(region = page->cache_ref->region_list; region; region = region->cache_next) {
|
||||
if(page->offset > region->cache_offset
|
||||
&& page->offset < region->cache_offset + region->size) {
|
||||
vm_translation_map *map = ®ion->aspace->translation_map;
|
||||
map->ops->lock(map);
|
||||
map->ops->clear_flags(map, page->offset - region->cache_offset + region->base, PAGE_MODIFIED);
|
||||
map->ops->unlock(map);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&page->cache_ref->lock);
|
||||
|
||||
/* write the page out to it's backing store */
|
||||
vecs->num = 1;
|
||||
vecs->total_len = PAGE_SIZE;
|
||||
vm_get_physical_page(page->physical_page_number * PAGE_SIZE, (addr_t *)&vecs->vec[0].iov_base, PHYSICAL_PAGE_CAN_WAIT);
|
||||
vecs->vec[0].iov_len = PAGE_SIZE;
|
||||
|
||||
err = page->cache_ref->cache->store->ops->write(page->cache_ref->cache->store, page->offset, vecs);
|
||||
|
||||
vm_put_physical_page((addr_t)vecs->vec[0].iov_base);
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
if(page->ref_count > 0) {
|
||||
page->state = PAGE_STATE_ACTIVE;
|
||||
} else {
|
||||
page->state = PAGE_STATE_INACTIVE;
|
||||
}
|
||||
enqueue_page(&page_active_queue, page);
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
|
||||
vm_cache_release_ref(page->cache_ref);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
vm_page_init_num_pages(kernel_args *args)
|
||||
{
|
||||
@ -403,6 +714,8 @@ vm_page_init(kernel_args *args)
|
||||
sPages[i].type = PAGE_TYPE_PHYSICAL;
|
||||
sPages[i].state = PAGE_STATE_FREE;
|
||||
sPages[i].ref_count = 0;
|
||||
sPages[i].wired_count = 0;
|
||||
sPages[i].usage_count = 0;
|
||||
enqueue_page(&page_free_queue, &sPages[i]);
|
||||
}
|
||||
|
||||
@ -458,83 +771,6 @@ vm_page_init_post_thread(kernel_args *args)
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
This is a background thread that wakes up every now and then (every 100ms)
|
||||
and moves some pages from the free queue over to the clear queue.
|
||||
Given enough time, it will clear out all pages from the free queue - we
|
||||
could probably slow it down after having reached a certain threshold.
|
||||
*/
|
||||
static int32
|
||||
page_scrubber(void *unused)
|
||||
{
|
||||
(void)(unused);
|
||||
|
||||
TRACE(("page_scrubber starting...\n"));
|
||||
|
||||
for (;;) {
|
||||
snooze(100000); // 100ms
|
||||
|
||||
if (page_free_queue.count > 0) {
|
||||
cpu_status state;
|
||||
vm_page *page[SCRUB_SIZE];
|
||||
int32 i, scrubCount;
|
||||
|
||||
// get some pages from the free queue
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
|
||||
for (i = 0; i < SCRUB_SIZE; i++) {
|
||||
page[i] = dequeue_page(&page_free_queue);
|
||||
if (page[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
|
||||
// clear them
|
||||
|
||||
scrubCount = i;
|
||||
|
||||
for (i = 0; i < scrubCount; i++) {
|
||||
clear_page(page[i]->physical_page_number * B_PAGE_SIZE);
|
||||
}
|
||||
|
||||
state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
|
||||
// and put them into the clear queue
|
||||
|
||||
for (i = 0; i < scrubCount; i++) {
|
||||
page[i]->state = PAGE_STATE_CLEAR;
|
||||
enqueue_page(&page_clear_queue, page[i]);
|
||||
}
|
||||
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
clear_page(addr_t pa)
|
||||
{
|
||||
addr_t va;
|
||||
|
||||
// dprintf("clear_page: clearing page 0x%x\n", pa);
|
||||
|
||||
vm_get_physical_page(pa, &va, PHYSICAL_PAGE_CAN_WAIT);
|
||||
|
||||
memset((void *)va, 0, B_PAGE_SIZE);
|
||||
|
||||
vm_put_physical_page(va);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
vm_mark_page_inuse(addr_t page)
|
||||
{
|
||||
@ -569,7 +805,7 @@ vm_mark_page_range_inuse(addr_t start_page, addr_t length)
|
||||
switch (page->state) {
|
||||
case PAGE_STATE_FREE:
|
||||
case PAGE_STATE_CLEAR:
|
||||
vm_page_set_state_nolock(page, PAGE_STATE_UNUSED);
|
||||
set_page_state_nolock(page, PAGE_STATE_UNUSED);
|
||||
break;
|
||||
case PAGE_STATE_WIRED:
|
||||
break;
|
||||
@ -755,8 +991,9 @@ vm_page_allocate_page_run(int page_state, addr_t len)
|
||||
}
|
||||
if (foundit) {
|
||||
// pull the pages out of the appropriate queues
|
||||
for (i = 0; i < len; i++)
|
||||
vm_page_set_state_nolock(&sPages[start + i], PAGE_STATE_BUSY);
|
||||
for (i = 0; i < len; i++) {
|
||||
set_page_state_nolock(&sPages[start + i], PAGE_STATE_BUSY);
|
||||
}
|
||||
first_page = &sPages[start];
|
||||
break;
|
||||
} else {
|
||||
@ -784,60 +1021,6 @@ vm_lookup_page(addr_t page_num)
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
vm_page_set_state_nolock(vm_page *page, int page_state)
|
||||
{
|
||||
page_queue *from_q = NULL;
|
||||
page_queue *to_q = NULL;
|
||||
|
||||
switch (page->state) {
|
||||
case PAGE_STATE_BUSY:
|
||||
case PAGE_STATE_ACTIVE:
|
||||
case PAGE_STATE_INACTIVE:
|
||||
case PAGE_STATE_WIRED:
|
||||
case PAGE_STATE_UNUSED:
|
||||
from_q = &page_active_queue;
|
||||
break;
|
||||
case PAGE_STATE_MODIFIED:
|
||||
from_q = &page_modified_queue;
|
||||
break;
|
||||
case PAGE_STATE_FREE:
|
||||
from_q = &page_free_queue;
|
||||
break;
|
||||
case PAGE_STATE_CLEAR:
|
||||
from_q = &page_clear_queue;
|
||||
break;
|
||||
default:
|
||||
panic("vm_page_set_state: vm_page %p in invalid state %d\n", page, page->state);
|
||||
}
|
||||
|
||||
switch (page_state) {
|
||||
case PAGE_STATE_BUSY:
|
||||
case PAGE_STATE_ACTIVE:
|
||||
case PAGE_STATE_INACTIVE:
|
||||
case PAGE_STATE_WIRED:
|
||||
case PAGE_STATE_UNUSED:
|
||||
to_q = &page_active_queue;
|
||||
break;
|
||||
case PAGE_STATE_MODIFIED:
|
||||
to_q = &page_modified_queue;
|
||||
break;
|
||||
case PAGE_STATE_FREE:
|
||||
to_q = &page_free_queue;
|
||||
break;
|
||||
case PAGE_STATE_CLEAR:
|
||||
to_q = &page_clear_queue;
|
||||
break;
|
||||
default:
|
||||
panic("vm_page_set_state: invalid target state %d\n", page_state);
|
||||
}
|
||||
page->state = page_state;
|
||||
move_page_to_queue(from_q, to_q, page);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
vm_page_set_state(vm_page *page, int page_state)
|
||||
{
|
||||
@ -846,7 +1029,7 @@ vm_page_set_state(vm_page *page, int page_state)
|
||||
cpu_status state = disable_interrupts();
|
||||
acquire_spinlock(&sPageLock);
|
||||
|
||||
status = vm_page_set_state_nolock(page, page_state);
|
||||
status = set_page_state_nolock(page, page_state);
|
||||
|
||||
release_spinlock(&sPageLock);
|
||||
restore_interrupts(state);
|
||||
@ -868,188 +1051,3 @@ vm_page_num_free_pages(void)
|
||||
return page_free_queue.count + page_clear_queue.count;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_free_page_table(int argc, char **argv)
|
||||
{
|
||||
dprintf("not finished\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_page(int argc, char **argv)
|
||||
{
|
||||
struct vm_page *page;
|
||||
addr_t address;
|
||||
bool physical = false;
|
||||
int32 index = 1;
|
||||
|
||||
if (argc > 2) {
|
||||
if (!strcmp(argv[1], "-p")) {
|
||||
physical = true;
|
||||
index++;
|
||||
} else if (!strcmp(argv[1], "-v"))
|
||||
index++;
|
||||
}
|
||||
|
||||
if (argc < 2
|
||||
|| strlen(argv[index]) <= 2
|
||||
|| argv[index][0] != '0'
|
||||
|| argv[index][1] != 'x') {
|
||||
kprintf("usage: page [-p|-v] <address>\n"
|
||||
" -v looks up a virtual address for the page, -p a physical address.\n"
|
||||
" Default is to look for the page structure address directly\n.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
address = strtoul(argv[index], NULL, 0);
|
||||
|
||||
if (index == 2) {
|
||||
if (!physical) {
|
||||
vm_address_space *addressSpace = vm_kernel_address_space();
|
||||
if (thread_get_current_thread()->team->address_space != NULL)
|
||||
addressSpace = thread_get_current_thread()->team->address_space;
|
||||
|
||||
addressSpace->translation_map.ops->query_interrupt(
|
||||
&addressSpace->translation_map, address, &address);
|
||||
|
||||
}
|
||||
page = vm_lookup_page(address / B_PAGE_SIZE);
|
||||
} else
|
||||
page = (struct vm_page *)address;
|
||||
|
||||
kprintf("PAGE: %p\n", page);
|
||||
kprintf("queue_next,prev: %p, %p\n", page->queue_next, page->queue_prev);
|
||||
kprintf("hash_next: %p\n", page->hash_next);
|
||||
kprintf("physical_number: %lx\n", page->physical_page_number);
|
||||
kprintf("cache: %p\n", page->cache);
|
||||
kprintf("cache_offset: %ld\n", page->cache_offset);
|
||||
kprintf("cache_next,prev: %p, %p\n", page->cache_next, page->cache_prev);
|
||||
kprintf("ref_count: %ld\n", page->ref_count);
|
||||
kprintf("type: %d\n", page->type);
|
||||
kprintf("state: %d\n", page->state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_page_queue(int argc, char **argv)
|
||||
{
|
||||
struct page_queue *queue;
|
||||
|
||||
if (argc < 2) {
|
||||
kprintf("usage: page_queue <address/name> [list]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strlen(argv[1]) >= 2 && argv[1][0] == '0' && argv[1][1] == 'x')
|
||||
queue = (struct page_queue *)strtoul(argv[1], NULL, 16);
|
||||
if (!strcmp(argv[1], "free"))
|
||||
queue = &page_free_queue;
|
||||
else if (!strcmp(argv[1], "clear"))
|
||||
queue = &page_clear_queue;
|
||||
else if (!strcmp(argv[1], "modified"))
|
||||
queue = &page_modified_queue;
|
||||
else if (!strcmp(argv[1], "active"))
|
||||
queue = &page_active_queue;
|
||||
else {
|
||||
kprintf("page_queue: unknown queue \"%s\".\n", argv[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kprintf("queue->head = %p, queue->tail = %p, queue->count = %d\n", queue->head, queue->tail, queue->count);
|
||||
|
||||
if (argc == 3) {
|
||||
struct vm_page *page = queue->head;
|
||||
int i;
|
||||
|
||||
for (i = 0; page; i++, page = page->queue_next) {
|
||||
kprintf("%5d. queue_next = %p, queue_prev = %p, type = %d, state = %d\n", i, page->queue_next, page->queue_prev, page->type, page->state);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_page_stats(int argc, char **argv)
|
||||
{
|
||||
uint32 counter[8];
|
||||
int32 totalActive;
|
||||
addr_t i;
|
||||
|
||||
memset(counter, 0, sizeof(counter));
|
||||
|
||||
for (i = 0; i < sNumPages; i++) {
|
||||
if (sPages[i].state > 7)
|
||||
panic("page %li at %p has invalid state!\n", i, &sPages[i]);
|
||||
|
||||
counter[sPages[i].state]++;
|
||||
}
|
||||
|
||||
kprintf("page stats:\n");
|
||||
kprintf("active: %lu\ninactive: %lu\nbusy: %lu\nunused: %lu\n",
|
||||
counter[PAGE_STATE_ACTIVE], counter[PAGE_STATE_INACTIVE], counter[PAGE_STATE_BUSY], counter[PAGE_STATE_UNUSED]);
|
||||
kprintf("wired: %lu\nmodified: %lu\nfree: %lu\nclear: %lu\n",
|
||||
counter[PAGE_STATE_WIRED], counter[PAGE_STATE_MODIFIED], counter[PAGE_STATE_FREE], counter[PAGE_STATE_CLEAR]);
|
||||
|
||||
kprintf("\nfree_queue: %p, count = %d\n", &page_free_queue, page_free_queue.count);
|
||||
kprintf("clear_queue: %p, count = %d\n", &page_clear_queue, page_clear_queue.count);
|
||||
kprintf("modified_queue: %p, count = %d\n", &page_modified_queue, page_modified_queue.count);
|
||||
kprintf("active_queue: %p, count = %d\n", &page_active_queue, page_active_queue.count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static int dump_free_page_table(int argc, char **argv)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
unsigned int free_start = END_OF_LIST;
|
||||
unsigned int inuse_start = PAGE_INUSE;
|
||||
|
||||
dprintf("dump_free_page_table():\n");
|
||||
dprintf("first_free_page_index = %d\n", first_free_page_index);
|
||||
|
||||
while(i < free_page_table_size) {
|
||||
if(free_page_table[i] == PAGE_INUSE) {
|
||||
if(inuse_start != PAGE_INUSE) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if(free_start != END_OF_LIST) {
|
||||
dprintf("free from %d -> %d\n", free_start + free_page_table_base, i-1 + free_page_table_base);
|
||||
free_start = END_OF_LIST;
|
||||
}
|
||||
inuse_start = i;
|
||||
} else {
|
||||
if(free_start != END_OF_LIST) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if(inuse_start != PAGE_INUSE) {
|
||||
dprintf("inuse from %d -> %d\n", inuse_start + free_page_table_base, i-1 + free_page_table_base);
|
||||
inuse_start = PAGE_INUSE;
|
||||
}
|
||||
free_start = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(inuse_start != PAGE_INUSE) {
|
||||
dprintf("inuse from %d -> %d\n", inuse_start + free_page_table_base, i-1 + free_page_table_base);
|
||||
}
|
||||
if(free_start != END_OF_LIST) {
|
||||
dprintf("free from %d -> %d\n", free_start + free_page_table_base, i-1 + free_page_table_base);
|
||||
}
|
||||
/*
|
||||
for(i=0; i<free_page_table_size; i++) {
|
||||
dprintf("%d->%d ", i, free_page_table[i]);
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user