2011-03-30 12:46:40 +00:00
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "../port/error.h"
|
|
|
|
|
|
|
|
#define pghash(daddr) palloc.hash[(daddr>>PGSHIFT)&(PGHSIZE-1)]
|
|
|
|
|
|
|
|
struct Palloc palloc;
|
|
|
|
|
|
|
|
void
|
|
|
|
pageinit(void)
|
|
|
|
{
|
|
|
|
int color, i, j;
|
|
|
|
Page *p;
|
|
|
|
Pallocmem *pm;
|
|
|
|
ulong m, np, k, vkb, pkb;
|
|
|
|
|
|
|
|
np = 0;
|
|
|
|
for(i=0; i<nelem(palloc.mem); i++){
|
|
|
|
pm = &palloc.mem[i];
|
|
|
|
np += pm->npage;
|
|
|
|
}
|
|
|
|
palloc.pages = xalloc(np*sizeof(Page));
|
|
|
|
if(palloc.pages == 0)
|
|
|
|
panic("pageinit");
|
|
|
|
|
|
|
|
color = 0;
|
|
|
|
palloc.head = palloc.pages;
|
|
|
|
p = palloc.head;
|
|
|
|
for(i=0; i<nelem(palloc.mem); i++){
|
|
|
|
pm = &palloc.mem[i];
|
|
|
|
for(j=0; j<pm->npage; j++){
|
|
|
|
p->prev = p-1;
|
|
|
|
p->next = p+1;
|
|
|
|
p->pa = pm->base+j*BY2PG;
|
|
|
|
p->color = color;
|
|
|
|
palloc.freecount++;
|
|
|
|
color = (color+1)%NCOLOR;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
palloc.tail = p - 1;
|
|
|
|
palloc.head->prev = 0;
|
|
|
|
palloc.tail->next = 0;
|
|
|
|
|
|
|
|
palloc.user = p - palloc.pages;
|
|
|
|
pkb = palloc.user*BY2PG/1024;
|
|
|
|
vkb = pkb + (conf.nswap*BY2PG)/1024;
|
|
|
|
|
|
|
|
/* Paging numbers */
|
|
|
|
swapalloc.highwater = (palloc.user*5)/100;
|
|
|
|
swapalloc.headroom = swapalloc.highwater + (swapalloc.highwater/4);
|
|
|
|
|
|
|
|
m = 0;
|
|
|
|
for(i=0; i<nelem(conf.mem); i++)
|
|
|
|
if(conf.mem[i].npage)
|
|
|
|
m += conf.mem[i].npage*BY2PG;
|
|
|
|
k = PGROUND(end - (char*)KTZERO);
|
|
|
|
print("%ldM memory: ", (m+k+1024*1024-1)/(1024*1024));
|
|
|
|
print("%ldM kernel data, ", (m+k-pkb*1024+1024*1024-1)/(1024*1024));
|
|
|
|
print("%ldM user, ", pkb/1024);
|
|
|
|
print("%ldM swap\n", vkb/1024);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pageunchain(Page *p)
|
|
|
|
{
|
|
|
|
if(canlock(&palloc))
|
|
|
|
panic("pageunchain (palloc %p)", &palloc);
|
|
|
|
if(p->prev)
|
|
|
|
p->prev->next = p->next;
|
|
|
|
else
|
|
|
|
palloc.head = p->next;
|
|
|
|
if(p->next)
|
|
|
|
p->next->prev = p->prev;
|
|
|
|
else
|
|
|
|
palloc.tail = p->prev;
|
|
|
|
p->prev = p->next = nil;
|
|
|
|
palloc.freecount--;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pagechaintail(Page *p)
|
|
|
|
{
|
|
|
|
if(canlock(&palloc))
|
|
|
|
panic("pagechaintail");
|
|
|
|
if(palloc.tail) {
|
|
|
|
p->prev = palloc.tail;
|
|
|
|
palloc.tail->next = p;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
palloc.head = p;
|
|
|
|
p->prev = 0;
|
|
|
|
}
|
|
|
|
palloc.tail = p;
|
|
|
|
p->next = 0;
|
|
|
|
palloc.freecount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pagechainhead(Page *p)
|
|
|
|
{
|
|
|
|
if(canlock(&palloc))
|
|
|
|
panic("pagechainhead");
|
|
|
|
if(palloc.head) {
|
|
|
|
p->next = palloc.head;
|
|
|
|
palloc.head->prev = p;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
palloc.tail = p;
|
|
|
|
p->next = 0;
|
|
|
|
}
|
|
|
|
palloc.head = p;
|
|
|
|
p->prev = 0;
|
|
|
|
palloc.freecount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
Page*
|
|
|
|
newpage(int clear, Segment **s, ulong va)
|
|
|
|
{
|
|
|
|
Page *p;
|
|
|
|
KMap *k;
|
|
|
|
uchar ct;
|
2011-08-24 12:43:15 +00:00
|
|
|
int i, hw, color;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
lock(&palloc);
|
|
|
|
color = getpgcolor(va);
|
|
|
|
hw = swapalloc.highwater;
|
|
|
|
for(;;) {
|
|
|
|
if(palloc.freecount > hw)
|
|
|
|
break;
|
|
|
|
if(up->kp && palloc.freecount > 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
unlock(&palloc);
|
2011-08-24 12:43:15 +00:00
|
|
|
if(s)
|
2011-03-30 12:46:40 +00:00
|
|
|
qunlock(&((*s)->lk));
|
|
|
|
|
2011-08-24 12:43:15 +00:00
|
|
|
if(!waserror()){
|
|
|
|
eqlock(&palloc.pwait); /* Hold memory requesters here */
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-08-24 12:43:15 +00:00
|
|
|
if(!waserror()){
|
|
|
|
kickpager();
|
|
|
|
tsleep(&palloc.r, ispages, 0, 1000);
|
|
|
|
poperror();
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-08-24 12:43:15 +00:00
|
|
|
qunlock(&palloc.pwait);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2011-08-24 12:43:15 +00:00
|
|
|
poperror();
|
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If called from fault and we lost the segment from
|
|
|
|
* underneath don't waste time allocating and freeing
|
|
|
|
* a page. Fault will call newpage again when it has
|
|
|
|
* reacquired the segment locks
|
|
|
|
*/
|
2011-08-24 12:43:15 +00:00
|
|
|
if(s){
|
|
|
|
*s = 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
return 0;
|
2011-08-24 12:43:15 +00:00
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
lock(&palloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First try for our colour */
|
|
|
|
for(p = palloc.head; p; p = p->next)
|
|
|
|
if(p->color == color)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ct = PG_NOFLUSH;
|
|
|
|
if(p == 0) {
|
|
|
|
p = palloc.head;
|
|
|
|
p->color = color;
|
|
|
|
ct = PG_NEWCOL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pageunchain(p);
|
|
|
|
|
|
|
|
lock(p);
|
|
|
|
if(p->ref != 0)
|
|
|
|
panic("newpage: p->ref %d != 0", p->ref);
|
|
|
|
|
|
|
|
uncachepage(p);
|
|
|
|
p->ref++;
|
|
|
|
p->va = va;
|
|
|
|
p->modref = 0;
|
|
|
|
for(i = 0; i < MAXMACH; i++)
|
|
|
|
p->cachectl[i] = ct;
|
|
|
|
unlock(p);
|
|
|
|
unlock(&palloc);
|
|
|
|
|
|
|
|
if(clear) {
|
|
|
|
k = kmap(p);
|
|
|
|
memset((void*)VA(k), 0, BY2PG);
|
|
|
|
kunmap(k);
|
|
|
|
}
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ispages(void*)
|
|
|
|
{
|
|
|
|
return palloc.freecount >= swapalloc.highwater;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
putpage(Page *p)
|
|
|
|
{
|
|
|
|
if(onswap(p)) {
|
|
|
|
putswap(p);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
lock(&palloc);
|
|
|
|
lock(p);
|
|
|
|
|
|
|
|
if(p->ref == 0)
|
|
|
|
panic("putpage");
|
|
|
|
|
|
|
|
if(--p->ref > 0) {
|
|
|
|
unlock(p);
|
|
|
|
unlock(&palloc);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(p->image && p->image != &swapimage)
|
|
|
|
pagechaintail(p);
|
|
|
|
else
|
|
|
|
pagechainhead(p);
|
|
|
|
|
|
|
|
if(palloc.r.p != 0)
|
|
|
|
wakeup(&palloc.r);
|
|
|
|
|
|
|
|
unlock(p);
|
|
|
|
unlock(&palloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
Page*
|
|
|
|
auxpage(void)
|
|
|
|
{
|
|
|
|
Page *p;
|
|
|
|
|
|
|
|
lock(&palloc);
|
|
|
|
p = palloc.head;
|
|
|
|
if(palloc.freecount < swapalloc.highwater) {
|
|
|
|
unlock(&palloc);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
pageunchain(p);
|
|
|
|
|
|
|
|
lock(p);
|
|
|
|
if(p->ref != 0)
|
|
|
|
panic("auxpage");
|
|
|
|
p->ref++;
|
|
|
|
uncachepage(p);
|
|
|
|
unlock(p);
|
|
|
|
unlock(&palloc);
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dupretries = 15000;
|
|
|
|
|
2012-02-16 17:04:08 +00:00
|
|
|
void
|
2011-03-30 12:46:40 +00:00
|
|
|
duppage(Page *p) /* Always call with p locked */
|
|
|
|
{
|
|
|
|
Page *np;
|
|
|
|
int color;
|
|
|
|
int retries;
|
|
|
|
|
|
|
|
retries = 0;
|
|
|
|
retry:
|
2012-02-16 17:04:08 +00:00
|
|
|
/* don't dup pages that are shared or have no image */
|
|
|
|
if(p->ref != 1 || p->image == nil || p->image->notext)
|
|
|
|
return;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
if(retries++ > dupretries){
|
|
|
|
print("duppage %d, up %p\n", retries, up);
|
|
|
|
dupretries += 100;
|
|
|
|
if(dupretries > 100000)
|
2012-02-16 17:04:08 +00:00
|
|
|
panic("duppage");
|
2011-03-30 12:46:40 +00:00
|
|
|
uncachepage(p);
|
2012-02-16 17:04:08 +00:00
|
|
|
return;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* normal lock ordering is to call
|
|
|
|
* lock(&palloc) before lock(p).
|
|
|
|
* To avoid deadlock, we have to drop
|
2012-02-16 17:04:08 +00:00
|
|
|
* our locks and try again. as the page
|
|
|
|
* is from the image cache, this might
|
|
|
|
* let someone else come in and grab it
|
|
|
|
* so we check page ref above.
|
2011-03-30 12:46:40 +00:00
|
|
|
*/
|
|
|
|
if(!canlock(&palloc)){
|
|
|
|
unlock(p);
|
|
|
|
if(up)
|
|
|
|
sched();
|
|
|
|
lock(p);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No freelist cache when memory is very low */
|
|
|
|
if(palloc.freecount < swapalloc.highwater) {
|
|
|
|
unlock(&palloc);
|
|
|
|
uncachepage(p);
|
2012-02-16 17:04:08 +00:00
|
|
|
return;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
color = getpgcolor(p->va);
|
|
|
|
for(np = palloc.head; np; np = np->next)
|
|
|
|
if(np->color == color)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* No page of the correct color */
|
|
|
|
if(np == 0) {
|
|
|
|
unlock(&palloc);
|
|
|
|
uncachepage(p);
|
2012-02-16 17:04:08 +00:00
|
|
|
return;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pageunchain(np);
|
|
|
|
pagechaintail(np);
|
|
|
|
/*
|
|
|
|
* XXX - here's a bug? - np is on the freelist but it's not really free.
|
|
|
|
* when we unlock palloc someone else can come in, decide to
|
|
|
|
* use np, and then try to lock it. they succeed after we've
|
|
|
|
* run copypage and cachepage and unlock(np). then what?
|
|
|
|
* they call pageunchain before locking(np), so it's removed
|
|
|
|
* from the freelist, but still in the cache because of
|
|
|
|
* cachepage below. if someone else looks in the cache
|
|
|
|
* before they remove it, the page will have a nonzero ref
|
|
|
|
* once they finally lock(np).
|
|
|
|
*/
|
|
|
|
lock(np);
|
2012-02-16 10:38:50 +00:00
|
|
|
if(np->ref != 0) /* should never happen */
|
2012-02-16 17:04:08 +00:00
|
|
|
panic("duppage: np->ref %d != 0", np->ref);
|
2011-03-30 12:46:40 +00:00
|
|
|
unlock(&palloc);
|
|
|
|
|
|
|
|
/* Cache the new version */
|
|
|
|
uncachepage(np);
|
|
|
|
np->va = p->va;
|
|
|
|
np->daddr = p->daddr;
|
|
|
|
copypage(p, np);
|
|
|
|
cachepage(np, p->image);
|
|
|
|
unlock(np);
|
|
|
|
uncachepage(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
copypage(Page *f, Page *t)
|
|
|
|
{
|
|
|
|
KMap *ks, *kd;
|
|
|
|
|
|
|
|
ks = kmap(f);
|
|
|
|
kd = kmap(t);
|
|
|
|
memmove((void*)VA(kd), (void*)VA(ks), BY2PG);
|
|
|
|
kunmap(ks);
|
|
|
|
kunmap(kd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
uncachepage(Page *p) /* Always called with a locked page */
|
|
|
|
{
|
|
|
|
Page **l, *f;
|
|
|
|
|
|
|
|
if(p->image == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
lock(&palloc.hashlock);
|
|
|
|
l = &pghash(p->daddr);
|
|
|
|
for(f = *l; f; f = f->hash) {
|
|
|
|
if(f == p) {
|
|
|
|
*l = p->hash;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
l = &f->hash;
|
|
|
|
}
|
|
|
|
unlock(&palloc.hashlock);
|
|
|
|
putimage(p->image);
|
|
|
|
p->image = 0;
|
|
|
|
p->daddr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cachepage(Page *p, Image *i)
|
|
|
|
{
|
|
|
|
Page **l;
|
|
|
|
|
|
|
|
/* If this ever happens it should be fixed by calling
|
|
|
|
* uncachepage instead of panic. I think there is a race
|
|
|
|
* with pio in which this can happen. Calling uncachepage is
|
|
|
|
* correct - I just wanted to see if we got here.
|
|
|
|
*/
|
|
|
|
if(p->image)
|
|
|
|
panic("cachepage");
|
|
|
|
|
|
|
|
incref(i);
|
|
|
|
lock(&palloc.hashlock);
|
|
|
|
p->image = i;
|
|
|
|
l = &pghash(p->daddr);
|
|
|
|
p->hash = *l;
|
|
|
|
*l = p;
|
|
|
|
unlock(&palloc.hashlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cachedel(Image *i, ulong daddr)
|
|
|
|
{
|
|
|
|
Page *f, **l;
|
|
|
|
|
|
|
|
lock(&palloc.hashlock);
|
|
|
|
l = &pghash(daddr);
|
|
|
|
for(f = *l; f; f = f->hash) {
|
|
|
|
if(f->image == i && f->daddr == daddr) {
|
|
|
|
lock(f);
|
|
|
|
if(f->image == i && f->daddr == daddr){
|
|
|
|
*l = f->hash;
|
|
|
|
putimage(f->image);
|
|
|
|
f->image = 0;
|
|
|
|
f->daddr = 0;
|
|
|
|
}
|
|
|
|
unlock(f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
l = &f->hash;
|
|
|
|
}
|
|
|
|
unlock(&palloc.hashlock);
|
|
|
|
}
|
|
|
|
|
|
|
|
Page *
|
|
|
|
lookpage(Image *i, ulong daddr)
|
|
|
|
{
|
|
|
|
Page *f;
|
|
|
|
|
|
|
|
lock(&palloc.hashlock);
|
|
|
|
for(f = pghash(daddr); f; f = f->hash) {
|
|
|
|
if(f->image == i && f->daddr == daddr) {
|
|
|
|
unlock(&palloc.hashlock);
|
|
|
|
|
|
|
|
lock(&palloc);
|
|
|
|
lock(f);
|
|
|
|
if(f->image != i || f->daddr != daddr) {
|
|
|
|
unlock(f);
|
|
|
|
unlock(&palloc);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(++f->ref == 1)
|
|
|
|
pageunchain(f);
|
|
|
|
unlock(&palloc);
|
|
|
|
unlock(f);
|
|
|
|
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unlock(&palloc.hashlock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Pte*
|
|
|
|
ptecpy(Pte *old)
|
|
|
|
{
|
|
|
|
Pte *new;
|
|
|
|
Page **src, **dst;
|
|
|
|
|
|
|
|
new = ptealloc();
|
|
|
|
dst = &new->pages[old->first-old->pages];
|
|
|
|
new->first = dst;
|
|
|
|
for(src = old->first; src <= old->last; src++, dst++)
|
|
|
|
if(*src) {
|
|
|
|
if(onswap(*src))
|
|
|
|
dupswap(*src);
|
|
|
|
else {
|
|
|
|
lock(*src);
|
|
|
|
(*src)->ref++;
|
|
|
|
unlock(*src);
|
|
|
|
}
|
|
|
|
new->last = dst;
|
|
|
|
*dst = *src;
|
|
|
|
}
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
Pte*
|
|
|
|
ptealloc(void)
|
|
|
|
{
|
|
|
|
Pte *new;
|
|
|
|
|
|
|
|
new = smalloc(sizeof(Pte));
|
|
|
|
new->first = &new->pages[PTEPERTAB];
|
|
|
|
new->last = new->pages;
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
freepte(Segment *s, Pte *p)
|
|
|
|
{
|
|
|
|
int ref;
|
|
|
|
void (*fn)(Page*);
|
|
|
|
Page *pt, **pg, **ptop;
|
|
|
|
|
|
|
|
switch(s->type&SG_TYPE) {
|
|
|
|
case SG_PHYSICAL:
|
|
|
|
fn = s->pseg->pgfree;
|
|
|
|
ptop = &p->pages[PTEPERTAB];
|
|
|
|
if(fn) {
|
|
|
|
for(pg = p->pages; pg < ptop; pg++) {
|
|
|
|
if(*pg == 0)
|
|
|
|
continue;
|
|
|
|
(*fn)(*pg);
|
|
|
|
*pg = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for(pg = p->pages; pg < ptop; pg++) {
|
|
|
|
pt = *pg;
|
|
|
|
if(pt == 0)
|
|
|
|
continue;
|
|
|
|
lock(pt);
|
|
|
|
ref = --pt->ref;
|
|
|
|
unlock(pt);
|
|
|
|
if(ref == 0)
|
|
|
|
free(pt);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
for(pg = p->first; pg <= p->last; pg++)
|
|
|
|
if(*pg) {
|
|
|
|
putpage(*pg);
|
|
|
|
*pg = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
ulong
|
|
|
|
pagenumber(Page *p)
|
|
|
|
{
|
|
|
|
return p-palloc.pages;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
checkpagerefs(void)
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
ulong i, np, nwrong;
|
|
|
|
ulong *ref;
|
|
|
|
|
|
|
|
np = palloc.user;
|
|
|
|
ref = malloc(np*sizeof ref[0]);
|
|
|
|
if(ref == nil){
|
|
|
|
print("checkpagerefs: out of memory\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This may not be exact if there are other processes
|
|
|
|
* holding refs to pages on their stacks. The hope is
|
|
|
|
* that if you run it on a quiescent system it will still
|
|
|
|
* be useful.
|
|
|
|
*/
|
|
|
|
s = splhi();
|
|
|
|
lock(&palloc);
|
|
|
|
countpagerefs(ref, 0);
|
|
|
|
portcountpagerefs(ref, 0);
|
|
|
|
nwrong = 0;
|
|
|
|
for(i=0; i<np; i++){
|
|
|
|
if(palloc.pages[i].ref != ref[i]){
|
|
|
|
iprint("page %#.8lux ref %d actual %lud\n",
|
|
|
|
palloc.pages[i].pa, palloc.pages[i].ref, ref[i]);
|
|
|
|
ref[i] = 1;
|
|
|
|
nwrong++;
|
|
|
|
}else
|
|
|
|
ref[i] = 0;
|
|
|
|
}
|
|
|
|
countpagerefs(ref, 1);
|
|
|
|
portcountpagerefs(ref, 1);
|
|
|
|
iprint("%lud mistakes found\n", nwrong);
|
|
|
|
unlock(&palloc);
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
portcountpagerefs(ulong *ref, int print)
|
|
|
|
{
|
|
|
|
ulong i, j, k, ns, n;
|
|
|
|
Page **pg, *entry;
|
|
|
|
Proc *p;
|
|
|
|
Pte *pte;
|
|
|
|
Segment *s;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pages in segments. s->mark avoids double-counting.
|
|
|
|
*/
|
|
|
|
n = 0;
|
|
|
|
ns = 0;
|
|
|
|
for(i=0; i<conf.nproc; i++){
|
|
|
|
p = proctab(i);
|
|
|
|
for(j=0; j<NSEG; j++){
|
|
|
|
s = p->seg[j];
|
|
|
|
if(s)
|
|
|
|
s->mark = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(i=0; i<conf.nproc; i++){
|
|
|
|
p = proctab(i);
|
|
|
|
for(j=0; j<NSEG; j++){
|
|
|
|
s = p->seg[j];
|
|
|
|
if(s == nil || s->mark++)
|
|
|
|
continue;
|
|
|
|
ns++;
|
|
|
|
for(k=0; k<s->mapsize; k++){
|
|
|
|
pte = s->map[k];
|
|
|
|
if(pte == nil)
|
|
|
|
continue;
|
|
|
|
for(pg = pte->first; pg <= pte->last; pg++){
|
|
|
|
entry = *pg;
|
|
|
|
if(pagedout(entry))
|
|
|
|
continue;
|
|
|
|
if(print){
|
|
|
|
if(ref[pagenumber(entry)])
|
|
|
|
iprint("page %#.8lux in segment %#p\n", entry->pa, s);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(ref[pagenumber(entry)]++ == 0)
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!print){
|
|
|
|
iprint("%lud pages in %lud segments\n", n, ns);
|
|
|
|
for(i=0; i<conf.nproc; i++){
|
|
|
|
p = proctab(i);
|
|
|
|
for(j=0; j<NSEG; j++){
|
|
|
|
s = p->seg[j];
|
|
|
|
if(s == nil)
|
|
|
|
continue;
|
|
|
|
if(s->ref != s->mark){
|
|
|
|
iprint("segment %#p (used by proc %lud pid %lud) has bad ref count %lud actual %lud\n",
|
|
|
|
s, i, p->pid, s->ref, s->mark);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|