From c004406e921901bcba035582727fc36693be7dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 28 Dec 2005 13:29:25 +0000 Subject: [PATCH] * Fixed a stupid bug in vm_page_write_modified() I introduced recently: if pages having the modified bit set were written back (that's the case when they weren't put into the modified pages queue yet), they were enqueued into the active queue twice, messing up the page lists with various effects - this little thing took me busy for the last few days :-/ * Improved the "page" debugger command: it now prints out much more info, and also lets you lookup pages via physical address. * The dump commands are now using kprintf() instead of dprintf(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15692 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/vm/vm_page.c | 87 ++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 29 deletions(-) diff --git a/src/system/kernel/vm/vm_page.c b/src/system/kernel/vm/vm_page.c index e060aa711f..a17debe301 100644 --- a/src/system/kernel/vm/vm_page.c +++ b/src/system/kernel/vm/vm_page.c @@ -63,6 +63,8 @@ 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 * dequeue_page(page_queue *q) { @@ -83,6 +85,8 @@ dequeue_page(page_queue *q) } +/** Enqueues a page to the head of the given queue */ + static void enqueue_page(page_queue *q, vm_page *page) { @@ -168,6 +172,7 @@ vm_page_write_modified(vm_cache *cache) for (; page; page = page->cache_next) { bool gotPage = false; + bool dequeuedPage = true; off_t pageOffset; status_t status; vm_area *area; @@ -207,8 +212,10 @@ vm_page_write_modified(vm_cache *cache) uint32 flags; map->ops->query(map, pageOffset - area->cache_offset + area->base, &physicalAddress, &flags); - if (flags & PAGE_MODIFIED) + if (flags & PAGE_MODIFIED) { gotPage = true; + dequeuedPage = false; + } } if (gotPage) { // clear the modified flag @@ -227,20 +234,22 @@ vm_page_write_modified(vm_cache *cache) mutex_lock(&cache->ref->lock); if (status == B_OK) { - // put it into the active queue + if (dequeuedPage) { + // put it into the active queue - state = disable_interrupts(); - acquire_spinlock(&page_lock); + state = disable_interrupts(); + acquire_spinlock(&page_lock); - if (page->ref_count > 0) - page->state = PAGE_STATE_ACTIVE; - else - page->state = PAGE_STATE_INACTIVE; + if (page->ref_count > 0) + page->state = PAGE_STATE_ACTIVE; + else + page->state = PAGE_STATE_INACTIVE; - enqueue_page(&page_active_queue, page); + enqueue_page(&page_active_queue, page); - release_spinlock(&page_lock); - restore_interrupts(state); + release_spinlock(&page_lock); + restore_interrupts(state); + } } else { // We don't have to put the PAGE_MODIFIED bit back, as it's still // in the modified pages list. @@ -810,8 +819,8 @@ vm_page_set_state_nolock(vm_page *page, int page_state) default: panic("vm_page_set_state: invalid target state %d\n", page_state); } - move_page_to_queue(from_q, to_q, page); page->state = page_state; + move_page_to_queue(from_q, to_q, page); return B_OK; } @@ -860,18 +869,38 @@ static int dump_page(int argc, char **argv) { struct vm_page *page; + addr_t address; + int32 index = 1; + + if (argc > 2 && !strncmp(argv[1], "lookup", strlen(argv[1]))) + index++; if (argc < 2 - || strlen(argv[1]) <= 2 - || argv[1][0] != '0' - || argv[1][1] != 'x') { - dprintf("usage: page_queue
\n"); + || strlen(argv[index]) <= 2 + || argv[index][0] != '0' + || argv[index][1] != 'x') { + kprintf("usage: page [lookup]
\n"); return 0; } - page = (struct vm_page *)(atoul(argv[1])); + address = strtoul(argv[index], NULL, 0); + + if (index == 2) + 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); - dprintf("queue_next = %p, queue_prev = %p, type = %d, state = %d\n", page->queue_next, page->queue_prev, page->type, page->state); return 0; } @@ -882,7 +911,7 @@ dump_page_queue(int argc, char **argv) struct page_queue *queue; if (argc < 2) { - dprintf("usage: page_queue
[list]\n"); + kprintf("usage: page_queue
[list]\n"); return 0; } @@ -897,18 +926,18 @@ dump_page_queue(int argc, char **argv) else if (!strcmp(argv[1], "active")) queue = &page_active_queue; else { - dprintf("page_queue: unknown queue \"%s\".\n", argv[1]); + kprintf("page_queue: unknown queue \"%s\".\n", argv[1]); return 0; } - dprintf("queue->head = %p, queue->tail = %p, queue->count = %d\n", queue->head, queue->tail, queue->count); + 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) { - dprintf("%5d. queue_next = %p, queue_prev = %p, type = %d, state = %d\n", i, page->queue_next, page->queue_prev, page->type, page->state); + 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; @@ -931,16 +960,16 @@ dump_page_stats(int argc, char **argv) counter[all_pages[i].state]++; } - dprintf("page stats:\n"); - dprintf("active: %lu\ninactive: %lu\nbusy: %lu\nunused: %lu\n", + 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]); - dprintf("wired: %lu\nmodified: %lu\nfree: %lu\nclear: %lu\n", + 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]); - dprintf("\nfree_queue: %p, count = %d\n", &page_free_queue, page_free_queue.count); - dprintf("clear_queue: %p, count = %d\n", &page_clear_queue, page_clear_queue.count); - dprintf("modified_queue: %p, count = %d\n", &page_modified_queue, page_modified_queue.count); - dprintf("active_queue: %p, count = %d\n", &page_active_queue, page_active_queue.count); + 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; }