* 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
This commit is contained in:
parent
e94a459785
commit
c004406e92
@ -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 <address>\n");
|
||||
|| strlen(argv[index]) <= 2
|
||||
|| argv[index][0] != '0'
|
||||
|| argv[index][1] != 'x') {
|
||||
kprintf("usage: page [lookup] <address>\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 <address/name> [list]\n");
|
||||
kprintf("usage: page_queue <address/name> [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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user