13e12c5d1SDavid du Colombier #include "u.h"
23e12c5d1SDavid du Colombier #include "../port/lib.h"
33e12c5d1SDavid du Colombier #include "mem.h"
43e12c5d1SDavid du Colombier #include "dat.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier #include "../port/error.h"
73e12c5d1SDavid du Colombier
8bd389b36SDavid du Colombier #define pghash(daddr) palloc.hash[(daddr>>PGSHIFT)&(PGHSIZE-1)]
93e12c5d1SDavid du Colombier
103e12c5d1SDavid du Colombier struct Palloc palloc;
113e12c5d1SDavid du Colombier
123e12c5d1SDavid du Colombier void
pageinit(void)133e12c5d1SDavid du Colombier pageinit(void)
143e12c5d1SDavid du Colombier {
154de34a7eSDavid du Colombier int color, i, j;
163e12c5d1SDavid du Colombier Page *p;
174de34a7eSDavid du Colombier Pallocmem *pm;
184de34a7eSDavid du Colombier ulong m, np, k, vkb, pkb;
193e12c5d1SDavid du Colombier
204de34a7eSDavid du Colombier np = 0;
214de34a7eSDavid du Colombier for(i=0; i<nelem(palloc.mem); i++){
224de34a7eSDavid du Colombier pm = &palloc.mem[i];
234de34a7eSDavid du Colombier np += pm->npage;
244de34a7eSDavid du Colombier }
25ea15f0ccSDavid du Colombier palloc.pages = xalloc(np*sizeof(Page));
26ea15f0ccSDavid du Colombier if(palloc.pages == 0)
273e12c5d1SDavid du Colombier panic("pageinit");
283e12c5d1SDavid du Colombier
297dd7cddfSDavid du Colombier color = 0;
30ea15f0ccSDavid du Colombier palloc.head = palloc.pages;
313e12c5d1SDavid du Colombier p = palloc.head;
324de34a7eSDavid du Colombier for(i=0; i<nelem(palloc.mem); i++){
334de34a7eSDavid du Colombier pm = &palloc.mem[i];
344de34a7eSDavid du Colombier for(j=0; j<pm->npage; j++){
353e12c5d1SDavid du Colombier p->prev = p-1;
363e12c5d1SDavid du Colombier p->next = p+1;
374de34a7eSDavid du Colombier p->pa = pm->base+j*BY2PG;
387dd7cddfSDavid du Colombier p->color = color;
397dd7cddfSDavid du Colombier palloc.freecount++;
407dd7cddfSDavid du Colombier color = (color+1)%NCOLOR;
413e12c5d1SDavid du Colombier p++;
423e12c5d1SDavid du Colombier }
433e12c5d1SDavid du Colombier }
443e12c5d1SDavid du Colombier palloc.tail = p - 1;
453e12c5d1SDavid du Colombier palloc.head->prev = 0;
463e12c5d1SDavid du Colombier palloc.tail->next = 0;
473e12c5d1SDavid du Colombier
48ea15f0ccSDavid du Colombier palloc.user = p - palloc.pages;
494de34a7eSDavid du Colombier pkb = palloc.user*BY2PG/1024;
504de34a7eSDavid du Colombier vkb = pkb + (conf.nswap*BY2PG)/1024;
513e12c5d1SDavid du Colombier
524de34a7eSDavid du Colombier /* Paging numbers */
537dd7cddfSDavid du Colombier swapalloc.highwater = (palloc.user*5)/100;
543e12c5d1SDavid du Colombier swapalloc.headroom = swapalloc.highwater + (swapalloc.highwater/4);
553e12c5d1SDavid du Colombier
564de34a7eSDavid du Colombier m = 0;
574de34a7eSDavid du Colombier for(i=0; i<nelem(conf.mem); i++)
584de34a7eSDavid du Colombier if(conf.mem[i].npage)
594de34a7eSDavid du Colombier m += conf.mem[i].npage*BY2PG;
604de34a7eSDavid du Colombier k = PGROUND(end - (char*)KTZERO);
614de34a7eSDavid du Colombier print("%ldM memory: ", (m+k+1024*1024-1)/(1024*1024));
624de34a7eSDavid du Colombier print("%ldM kernel data, ", (m+k-pkb*1024+1024*1024-1)/(1024*1024));
634de34a7eSDavid du Colombier print("%ldM user, ", pkb/1024);
644de34a7eSDavid du Colombier print("%ldM swap\n", vkb/1024);
657dd7cddfSDavid du Colombier }
663e12c5d1SDavid du Colombier
677dd7cddfSDavid du Colombier static void
pageunchain(Page * p)687dd7cddfSDavid du Colombier pageunchain(Page *p)
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier if(canlock(&palloc))
71dc5a79c1SDavid du Colombier panic("pageunchain (palloc %p)", &palloc);
727dd7cddfSDavid du Colombier if(p->prev)
737dd7cddfSDavid du Colombier p->prev->next = p->next;
747dd7cddfSDavid du Colombier else
757dd7cddfSDavid du Colombier palloc.head = p->next;
767dd7cddfSDavid du Colombier if(p->next)
777dd7cddfSDavid du Colombier p->next->prev = p->prev;
787dd7cddfSDavid du Colombier else
797dd7cddfSDavid du Colombier palloc.tail = p->prev;
807dd7cddfSDavid du Colombier p->prev = p->next = nil;
817dd7cddfSDavid du Colombier palloc.freecount--;
827dd7cddfSDavid du Colombier }
837dd7cddfSDavid du Colombier
847dd7cddfSDavid du Colombier void
pagechaintail(Page * p)857dd7cddfSDavid du Colombier pagechaintail(Page *p)
867dd7cddfSDavid du Colombier {
877dd7cddfSDavid du Colombier if(canlock(&palloc))
887dd7cddfSDavid du Colombier panic("pagechaintail");
897dd7cddfSDavid du Colombier if(palloc.tail) {
907dd7cddfSDavid du Colombier p->prev = palloc.tail;
917dd7cddfSDavid du Colombier palloc.tail->next = p;
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier else {
947dd7cddfSDavid du Colombier palloc.head = p;
957dd7cddfSDavid du Colombier p->prev = 0;
967dd7cddfSDavid du Colombier }
977dd7cddfSDavid du Colombier palloc.tail = p;
987dd7cddfSDavid du Colombier p->next = 0;
997dd7cddfSDavid du Colombier palloc.freecount++;
1007dd7cddfSDavid du Colombier }
1017dd7cddfSDavid du Colombier
1027dd7cddfSDavid du Colombier void
pagechainhead(Page * p)1037dd7cddfSDavid du Colombier pagechainhead(Page *p)
1047dd7cddfSDavid du Colombier {
1057dd7cddfSDavid du Colombier if(canlock(&palloc))
1067dd7cddfSDavid du Colombier panic("pagechainhead");
1077dd7cddfSDavid du Colombier if(palloc.head) {
1087dd7cddfSDavid du Colombier p->next = palloc.head;
1097dd7cddfSDavid du Colombier palloc.head->prev = p;
1107dd7cddfSDavid du Colombier }
1117dd7cddfSDavid du Colombier else {
1127dd7cddfSDavid du Colombier palloc.tail = p;
1137dd7cddfSDavid du Colombier p->next = 0;
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier palloc.head = p;
1167dd7cddfSDavid du Colombier p->prev = 0;
1177dd7cddfSDavid du Colombier palloc.freecount++;
1183e12c5d1SDavid du Colombier }
1193e12c5d1SDavid du Colombier
1203e12c5d1SDavid du Colombier Page*
newpage(int clear,Segment ** s,ulong va)1213e12c5d1SDavid du Colombier newpage(int clear, Segment **s, ulong va)
1223e12c5d1SDavid du Colombier {
1233e12c5d1SDavid du Colombier Page *p;
1243e12c5d1SDavid du Colombier KMap *k;
1257dd7cddfSDavid du Colombier uchar ct;
1267dd7cddfSDavid du Colombier int i, hw, dontalloc, color;
1273e12c5d1SDavid du Colombier
1283e12c5d1SDavid du Colombier lock(&palloc);
1297dd7cddfSDavid du Colombier color = getpgcolor(va);
1303e12c5d1SDavid du Colombier hw = swapalloc.highwater;
1317dd7cddfSDavid du Colombier for(;;) {
1327dd7cddfSDavid du Colombier if(palloc.freecount > hw)
1337dd7cddfSDavid du Colombier break;
1347dd7cddfSDavid du Colombier if(up->kp && palloc.freecount > 0)
1357dd7cddfSDavid du Colombier break;
1367dd7cddfSDavid du Colombier
1373e12c5d1SDavid du Colombier unlock(&palloc);
1383e12c5d1SDavid du Colombier dontalloc = 0;
1393e12c5d1SDavid du Colombier if(s && *s) {
1403e12c5d1SDavid du Colombier qunlock(&((*s)->lk));
1413e12c5d1SDavid du Colombier *s = 0;
1423e12c5d1SDavid du Colombier dontalloc = 1;
1433e12c5d1SDavid du Colombier }
1443e12c5d1SDavid du Colombier qlock(&palloc.pwait); /* Hold memory requesters here */
1453e12c5d1SDavid du Colombier
1463e12c5d1SDavid du Colombier while(waserror()) /* Ignore interrupts */
1473e12c5d1SDavid du Colombier ;
1483e12c5d1SDavid du Colombier
1493e12c5d1SDavid du Colombier kickpager();
1503e12c5d1SDavid du Colombier tsleep(&palloc.r, ispages, 0, 1000);
1513e12c5d1SDavid du Colombier
1523e12c5d1SDavid du Colombier poperror();
1533e12c5d1SDavid du Colombier
1543e12c5d1SDavid du Colombier qunlock(&palloc.pwait);
1553e12c5d1SDavid du Colombier
1563e12c5d1SDavid du Colombier /*
1577dd7cddfSDavid du Colombier * If called from fault and we lost the segment from
1587dd7cddfSDavid du Colombier * underneath don't waste time allocating and freeing
1597dd7cddfSDavid du Colombier * a page. Fault will call newpage again when it has
1607dd7cddfSDavid du Colombier * reacquired the segment locks
1613e12c5d1SDavid du Colombier */
1623e12c5d1SDavid du Colombier if(dontalloc)
1633e12c5d1SDavid du Colombier return 0;
1643e12c5d1SDavid du Colombier
1653e12c5d1SDavid du Colombier lock(&palloc);
1663e12c5d1SDavid du Colombier }
1673e12c5d1SDavid du Colombier
1687dd7cddfSDavid du Colombier /* First try for our colour */
1697dd7cddfSDavid du Colombier for(p = palloc.head; p; p = p->next)
1707dd7cddfSDavid du Colombier if(p->color == color)
1717dd7cddfSDavid du Colombier break;
1723e12c5d1SDavid du Colombier
1737dd7cddfSDavid du Colombier ct = PG_NOFLUSH;
1747dd7cddfSDavid du Colombier if(p == 0) {
1757dd7cddfSDavid du Colombier p = palloc.head;
1767dd7cddfSDavid du Colombier p->color = color;
1777dd7cddfSDavid du Colombier ct = PG_NEWCOL;
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier
1807dd7cddfSDavid du Colombier pageunchain(p);
1813e12c5d1SDavid du Colombier
1823e12c5d1SDavid du Colombier lock(p);
1837dd7cddfSDavid du Colombier if(p->ref != 0)
184*c6569576SDavid du Colombier panic("newpage: p->ref %d != 0", p->ref);
1857dd7cddfSDavid du Colombier
1863e12c5d1SDavid du Colombier uncachepage(p);
1873e12c5d1SDavid du Colombier p->ref++;
1883e12c5d1SDavid du Colombier p->va = va;
1893e12c5d1SDavid du Colombier p->modref = 0;
1903e12c5d1SDavid du Colombier for(i = 0; i < MAXMACH; i++)
1917dd7cddfSDavid du Colombier p->cachectl[i] = ct;
1923e12c5d1SDavid du Colombier unlock(p);
1937dd7cddfSDavid du Colombier unlock(&palloc);
1943e12c5d1SDavid du Colombier
1953e12c5d1SDavid du Colombier if(clear) {
1963e12c5d1SDavid du Colombier k = kmap(p);
1973e12c5d1SDavid du Colombier memset((void*)VA(k), 0, BY2PG);
1983e12c5d1SDavid du Colombier kunmap(k);
1993e12c5d1SDavid du Colombier }
2003e12c5d1SDavid du Colombier
2013e12c5d1SDavid du Colombier return p;
2023e12c5d1SDavid du Colombier }
2033e12c5d1SDavid du Colombier
2043e12c5d1SDavid du Colombier int
ispages(void *)2057dd7cddfSDavid du Colombier ispages(void*)
2063e12c5d1SDavid du Colombier {
2073e12c5d1SDavid du Colombier return palloc.freecount >= swapalloc.highwater;
2083e12c5d1SDavid du Colombier }
2093e12c5d1SDavid du Colombier
2103e12c5d1SDavid du Colombier void
putpage(Page * p)2113e12c5d1SDavid du Colombier putpage(Page *p)
2123e12c5d1SDavid du Colombier {
2133e12c5d1SDavid du Colombier if(onswap(p)) {
2143e12c5d1SDavid du Colombier putswap(p);
2153e12c5d1SDavid du Colombier return;
2163e12c5d1SDavid du Colombier }
2173e12c5d1SDavid du Colombier
2183e12c5d1SDavid du Colombier lock(&palloc);
2197dd7cddfSDavid du Colombier lock(p);
2203e12c5d1SDavid du Colombier
2217dd7cddfSDavid du Colombier if(p->ref == 0)
2227dd7cddfSDavid du Colombier panic("putpage");
2237dd7cddfSDavid du Colombier
2247dd7cddfSDavid du Colombier if(--p->ref > 0) {
2253e12c5d1SDavid du Colombier unlock(p);
2267dd7cddfSDavid du Colombier unlock(&palloc);
2273e12c5d1SDavid du Colombier return;
2283e12c5d1SDavid du Colombier }
2297dd7cddfSDavid du Colombier
2307dd7cddfSDavid du Colombier if(p->image && p->image != &swapimage)
2317dd7cddfSDavid du Colombier pagechaintail(p);
2327dd7cddfSDavid du Colombier else
2337dd7cddfSDavid du Colombier pagechainhead(p);
2347dd7cddfSDavid du Colombier
2357dd7cddfSDavid du Colombier if(palloc.r.p != 0)
2367dd7cddfSDavid du Colombier wakeup(&palloc.r);
2377dd7cddfSDavid du Colombier
2387dd7cddfSDavid du Colombier unlock(p);
2397dd7cddfSDavid du Colombier unlock(&palloc);
2407dd7cddfSDavid du Colombier }
2417dd7cddfSDavid du Colombier
2427dd7cddfSDavid du Colombier Page*
auxpage(void)24350e5f38dSDavid du Colombier auxpage(void)
2447dd7cddfSDavid du Colombier {
2457dd7cddfSDavid du Colombier Page *p;
2467dd7cddfSDavid du Colombier
2477dd7cddfSDavid du Colombier lock(&palloc);
2487dd7cddfSDavid du Colombier p = palloc.head;
2497dd7cddfSDavid du Colombier if(palloc.freecount < swapalloc.highwater) {
2507dd7cddfSDavid du Colombier unlock(&palloc);
2517dd7cddfSDavid du Colombier return 0;
2527dd7cddfSDavid du Colombier }
2537dd7cddfSDavid du Colombier pageunchain(p);
2547dd7cddfSDavid du Colombier
2557dd7cddfSDavid du Colombier lock(p);
2567dd7cddfSDavid du Colombier if(p->ref != 0)
2577dd7cddfSDavid du Colombier panic("auxpage");
2587dd7cddfSDavid du Colombier p->ref++;
2597dd7cddfSDavid du Colombier uncachepage(p);
2607dd7cddfSDavid du Colombier unlock(p);
2617dd7cddfSDavid du Colombier unlock(&palloc);
2627dd7cddfSDavid du Colombier
2637dd7cddfSDavid du Colombier return p;
2643e12c5d1SDavid du Colombier }
2653e12c5d1SDavid du Colombier
2665243b8d1SDavid du Colombier static int dupretries = 15000;
2675243b8d1SDavid du Colombier
2685243b8d1SDavid du Colombier int
duppage(Page * p)2693e12c5d1SDavid du Colombier duppage(Page *p) /* Always call with p locked */
2703e12c5d1SDavid du Colombier {
2713e12c5d1SDavid du Colombier Page *np;
2727dd7cddfSDavid du Colombier int color;
2737dd7cddfSDavid du Colombier int retries;
2743e12c5d1SDavid du Colombier
2757dd7cddfSDavid du Colombier retries = 0;
2767dd7cddfSDavid du Colombier retry:
2777dd7cddfSDavid du Colombier
2785243b8d1SDavid du Colombier if(retries++ > dupretries){
2795243b8d1SDavid du Colombier print("duppage %d, up %p\n", retries, up);
2805243b8d1SDavid du Colombier dupretries += 100;
2815243b8d1SDavid du Colombier if(dupretries > 100000)
2825243b8d1SDavid du Colombier panic("duppage\n");
2835243b8d1SDavid du Colombier uncachepage(p);
2845243b8d1SDavid du Colombier return 1;
2855243b8d1SDavid du Colombier }
2865243b8d1SDavid du Colombier
2877dd7cddfSDavid du Colombier
2887dd7cddfSDavid du Colombier /* don't dup pages with no image */
2897dd7cddfSDavid du Colombier if(p->ref == 0 || p->image == nil || p->image->notext)
2905243b8d1SDavid du Colombier return 0;
2917dd7cddfSDavid du Colombier
2927dd7cddfSDavid du Colombier /*
2937dd7cddfSDavid du Colombier * normal lock ordering is to call
2947dd7cddfSDavid du Colombier * lock(&palloc) before lock(p).
2957dd7cddfSDavid du Colombier * To avoid deadlock, we have to drop
2967dd7cddfSDavid du Colombier * our locks and try again.
2977dd7cddfSDavid du Colombier */
2987dd7cddfSDavid du Colombier if(!canlock(&palloc)){
2997dd7cddfSDavid du Colombier unlock(p);
3007dd7cddfSDavid du Colombier if(up)
3017dd7cddfSDavid du Colombier sched();
3027dd7cddfSDavid du Colombier lock(p);
3037dd7cddfSDavid du Colombier goto retry;
3043e12c5d1SDavid du Colombier }
3053e12c5d1SDavid du Colombier
3063e12c5d1SDavid du Colombier /* No freelist cache when memory is very low */
3073e12c5d1SDavid du Colombier if(palloc.freecount < swapalloc.highwater) {
3083e12c5d1SDavid du Colombier unlock(&palloc);
3093e12c5d1SDavid du Colombier uncachepage(p);
3105243b8d1SDavid du Colombier return 1;
3113e12c5d1SDavid du Colombier }
3123e12c5d1SDavid du Colombier
3137dd7cddfSDavid du Colombier color = getpgcolor(p->va);
3147dd7cddfSDavid du Colombier for(np = palloc.head; np; np = np->next)
3157dd7cddfSDavid du Colombier if(np->color == color)
3167dd7cddfSDavid du Colombier break;
3173e12c5d1SDavid du Colombier
3187dd7cddfSDavid du Colombier /* No page of the correct color */
3197dd7cddfSDavid du Colombier if(np == 0) {
3203e12c5d1SDavid du Colombier unlock(&palloc);
3213e12c5d1SDavid du Colombier uncachepage(p);
3225243b8d1SDavid du Colombier return 1;
3233e12c5d1SDavid du Colombier }
3243e12c5d1SDavid du Colombier
3257dd7cddfSDavid du Colombier pageunchain(np);
3267dd7cddfSDavid du Colombier pagechaintail(np);
327ea15f0ccSDavid du Colombier /*
328ea15f0ccSDavid du Colombier * XXX - here's a bug? - np is on the freelist but it's not really free.
329ea15f0ccSDavid du Colombier * when we unlock palloc someone else can come in, decide to
330ea15f0ccSDavid du Colombier * use np, and then try to lock it. they succeed after we've
331ea15f0ccSDavid du Colombier * run copypage and cachepage and unlock(np). then what?
332ea15f0ccSDavid du Colombier * they call pageunchain before locking(np), so it's removed
333ea15f0ccSDavid du Colombier * from the freelist, but still in the cache because of
334ea15f0ccSDavid du Colombier * cachepage below. if someone else looks in the cache
335ea15f0ccSDavid du Colombier * before they remove it, the page will have a nonzero ref
336ea15f0ccSDavid du Colombier * once they finally lock(np).
337ea15f0ccSDavid du Colombier */
3387dd7cddfSDavid du Colombier lock(np);
3397dd7cddfSDavid du Colombier unlock(&palloc);
3407dd7cddfSDavid du Colombier
3417dd7cddfSDavid du Colombier /* Cache the new version */
3423e12c5d1SDavid du Colombier uncachepage(np);
3433e12c5d1SDavid du Colombier np->va = p->va;
3443e12c5d1SDavid du Colombier np->daddr = p->daddr;
3453e12c5d1SDavid du Colombier copypage(p, np);
3463e12c5d1SDavid du Colombier cachepage(np, p->image);
3473e12c5d1SDavid du Colombier unlock(np);
3483e12c5d1SDavid du Colombier uncachepage(p);
3495243b8d1SDavid du Colombier
3505243b8d1SDavid du Colombier return 0;
3513e12c5d1SDavid du Colombier }
3523e12c5d1SDavid du Colombier
3533e12c5d1SDavid du Colombier void
copypage(Page * f,Page * t)3543e12c5d1SDavid du Colombier copypage(Page *f, Page *t)
3553e12c5d1SDavid du Colombier {
3563e12c5d1SDavid du Colombier KMap *ks, *kd;
3573e12c5d1SDavid du Colombier
3583e12c5d1SDavid du Colombier ks = kmap(f);
3593e12c5d1SDavid du Colombier kd = kmap(t);
3603e12c5d1SDavid du Colombier memmove((void*)VA(kd), (void*)VA(ks), BY2PG);
3613e12c5d1SDavid du Colombier kunmap(ks);
3623e12c5d1SDavid du Colombier kunmap(kd);
3633e12c5d1SDavid du Colombier }
3643e12c5d1SDavid du Colombier
3653e12c5d1SDavid du Colombier void
uncachepage(Page * p)3663e12c5d1SDavid du Colombier uncachepage(Page *p) /* Always called with a locked page */
3673e12c5d1SDavid du Colombier {
3683e12c5d1SDavid du Colombier Page **l, *f;
3693e12c5d1SDavid du Colombier
3703e12c5d1SDavid du Colombier if(p->image == 0)
3713e12c5d1SDavid du Colombier return;
3723e12c5d1SDavid du Colombier
3733e12c5d1SDavid du Colombier lock(&palloc.hashlock);
374bd389b36SDavid du Colombier l = &pghash(p->daddr);
3753e12c5d1SDavid du Colombier for(f = *l; f; f = f->hash) {
3763e12c5d1SDavid du Colombier if(f == p) {
3773e12c5d1SDavid du Colombier *l = p->hash;
3783e12c5d1SDavid du Colombier break;
3793e12c5d1SDavid du Colombier }
3803e12c5d1SDavid du Colombier l = &f->hash;
3813e12c5d1SDavid du Colombier }
3823e12c5d1SDavid du Colombier unlock(&palloc.hashlock);
3833e12c5d1SDavid du Colombier putimage(p->image);
3843e12c5d1SDavid du Colombier p->image = 0;
3857dd7cddfSDavid du Colombier p->daddr = 0;
3863e12c5d1SDavid du Colombier }
3873e12c5d1SDavid du Colombier
3883e12c5d1SDavid du Colombier void
cachepage(Page * p,Image * i)3893e12c5d1SDavid du Colombier cachepage(Page *p, Image *i)
3903e12c5d1SDavid du Colombier {
3913e12c5d1SDavid du Colombier Page **l;
3923e12c5d1SDavid du Colombier
393bd389b36SDavid du Colombier /* If this ever happens it should be fixed by calling
394bd389b36SDavid du Colombier * uncachepage instead of panic. I think there is a race
395bd389b36SDavid du Colombier * with pio in which this can happen. Calling uncachepage is
396bd389b36SDavid du Colombier * correct - I just wanted to see if we got here.
397bd389b36SDavid du Colombier */
398bd389b36SDavid du Colombier if(p->image)
399bd389b36SDavid du Colombier panic("cachepage");
400bd389b36SDavid du Colombier
4013e12c5d1SDavid du Colombier incref(i);
4023e12c5d1SDavid du Colombier lock(&palloc.hashlock);
4033e12c5d1SDavid du Colombier p->image = i;
404bd389b36SDavid du Colombier l = &pghash(p->daddr);
4053e12c5d1SDavid du Colombier p->hash = *l;
4063e12c5d1SDavid du Colombier *l = p;
4073e12c5d1SDavid du Colombier unlock(&palloc.hashlock);
4083e12c5d1SDavid du Colombier }
4093e12c5d1SDavid du Colombier
4103e12c5d1SDavid du Colombier void
cachedel(Image * i,ulong daddr)4113e12c5d1SDavid du Colombier cachedel(Image *i, ulong daddr)
4123e12c5d1SDavid du Colombier {
4133e12c5d1SDavid du Colombier Page *f, **l;
4143e12c5d1SDavid du Colombier
4153e12c5d1SDavid du Colombier lock(&palloc.hashlock);
416bd389b36SDavid du Colombier l = &pghash(daddr);
4173e12c5d1SDavid du Colombier for(f = *l; f; f = f->hash) {
4183e12c5d1SDavid du Colombier if(f->image == i && f->daddr == daddr) {
4197dd7cddfSDavid du Colombier lock(f);
4207dd7cddfSDavid du Colombier if(f->image == i && f->daddr == daddr){
4213e12c5d1SDavid du Colombier *l = f->hash;
4227dd7cddfSDavid du Colombier putimage(f->image);
4237dd7cddfSDavid du Colombier f->image = 0;
4247dd7cddfSDavid du Colombier f->daddr = 0;
4257dd7cddfSDavid du Colombier }
4267dd7cddfSDavid du Colombier unlock(f);
4273e12c5d1SDavid du Colombier break;
4283e12c5d1SDavid du Colombier }
4293e12c5d1SDavid du Colombier l = &f->hash;
4303e12c5d1SDavid du Colombier }
4313e12c5d1SDavid du Colombier unlock(&palloc.hashlock);
4323e12c5d1SDavid du Colombier }
4333e12c5d1SDavid du Colombier
4343e12c5d1SDavid du Colombier Page *
lookpage(Image * i,ulong daddr)4353e12c5d1SDavid du Colombier lookpage(Image *i, ulong daddr)
4363e12c5d1SDavid du Colombier {
4373e12c5d1SDavid du Colombier Page *f;
4383e12c5d1SDavid du Colombier
4393e12c5d1SDavid du Colombier lock(&palloc.hashlock);
440bd389b36SDavid du Colombier for(f = pghash(daddr); f; f = f->hash) {
4413e12c5d1SDavid du Colombier if(f->image == i && f->daddr == daddr) {
4423e12c5d1SDavid du Colombier unlock(&palloc.hashlock);
4433e12c5d1SDavid du Colombier
4447dd7cddfSDavid du Colombier lock(&palloc);
4453e12c5d1SDavid du Colombier lock(f);
4463e12c5d1SDavid du Colombier if(f->image != i || f->daddr != daddr) {
4473e12c5d1SDavid du Colombier unlock(f);
4487dd7cddfSDavid du Colombier unlock(&palloc);
4493e12c5d1SDavid du Colombier return 0;
4503e12c5d1SDavid du Colombier }
4517dd7cddfSDavid du Colombier if(++f->ref == 1)
4527dd7cddfSDavid du Colombier pageunchain(f);
4533e12c5d1SDavid du Colombier unlock(&palloc);
4543e12c5d1SDavid du Colombier unlock(f);
4557dd7cddfSDavid du Colombier
4563e12c5d1SDavid du Colombier return f;
4573e12c5d1SDavid du Colombier }
4583e12c5d1SDavid du Colombier }
4593e12c5d1SDavid du Colombier unlock(&palloc.hashlock);
4607dd7cddfSDavid du Colombier
4613e12c5d1SDavid du Colombier return 0;
4623e12c5d1SDavid du Colombier }
4633e12c5d1SDavid du Colombier
4643e12c5d1SDavid du Colombier Pte*
ptecpy(Pte * old)4653e12c5d1SDavid du Colombier ptecpy(Pte *old)
4663e12c5d1SDavid du Colombier {
4673e12c5d1SDavid du Colombier Pte *new;
4683e12c5d1SDavid du Colombier Page **src, **dst;
4693e12c5d1SDavid du Colombier
4703e12c5d1SDavid du Colombier new = ptealloc();
4713e12c5d1SDavid du Colombier dst = &new->pages[old->first-old->pages];
4723e12c5d1SDavid du Colombier new->first = dst;
4733e12c5d1SDavid du Colombier for(src = old->first; src <= old->last; src++, dst++)
4743e12c5d1SDavid du Colombier if(*src) {
4753e12c5d1SDavid du Colombier if(onswap(*src))
4763e12c5d1SDavid du Colombier dupswap(*src);
4773e12c5d1SDavid du Colombier else {
4783e12c5d1SDavid du Colombier lock(*src);
4793e12c5d1SDavid du Colombier (*src)->ref++;
4803e12c5d1SDavid du Colombier unlock(*src);
4813e12c5d1SDavid du Colombier }
4823e12c5d1SDavid du Colombier new->last = dst;
4833e12c5d1SDavid du Colombier *dst = *src;
4843e12c5d1SDavid du Colombier }
4853e12c5d1SDavid du Colombier
4863e12c5d1SDavid du Colombier return new;
4873e12c5d1SDavid du Colombier }
4883e12c5d1SDavid du Colombier
4893e12c5d1SDavid du Colombier Pte*
ptealloc(void)4903e12c5d1SDavid du Colombier ptealloc(void)
4913e12c5d1SDavid du Colombier {
4923e12c5d1SDavid du Colombier Pte *new;
4933e12c5d1SDavid du Colombier
4943e12c5d1SDavid du Colombier new = smalloc(sizeof(Pte));
4953e12c5d1SDavid du Colombier new->first = &new->pages[PTEPERTAB];
4963e12c5d1SDavid du Colombier new->last = new->pages;
4973e12c5d1SDavid du Colombier return new;
4983e12c5d1SDavid du Colombier }
4993e12c5d1SDavid du Colombier
5003e12c5d1SDavid du Colombier void
freepte(Segment * s,Pte * p)5013e12c5d1SDavid du Colombier freepte(Segment *s, Pte *p)
5023e12c5d1SDavid du Colombier {
503219b2ee8SDavid du Colombier int ref;
504219b2ee8SDavid du Colombier void (*fn)(Page*);
5057dd7cddfSDavid du Colombier Page *pt, **pg, **ptop;
5063e12c5d1SDavid du Colombier
5073e12c5d1SDavid du Colombier switch(s->type&SG_TYPE) {
5083e12c5d1SDavid du Colombier case SG_PHYSICAL:
509219b2ee8SDavid du Colombier fn = s->pseg->pgfree;
5103e12c5d1SDavid du Colombier ptop = &p->pages[PTEPERTAB];
511219b2ee8SDavid du Colombier if(fn) {
512219b2ee8SDavid du Colombier for(pg = p->pages; pg < ptop; pg++) {
513219b2ee8SDavid du Colombier if(*pg == 0)
514219b2ee8SDavid du Colombier continue;
515219b2ee8SDavid du Colombier (*fn)(*pg);
5163e12c5d1SDavid du Colombier *pg = 0;
5173e12c5d1SDavid du Colombier }
5183e12c5d1SDavid du Colombier break;
519219b2ee8SDavid du Colombier }
520219b2ee8SDavid du Colombier for(pg = p->pages; pg < ptop; pg++) {
521219b2ee8SDavid du Colombier pt = *pg;
522219b2ee8SDavid du Colombier if(pt == 0)
523219b2ee8SDavid du Colombier continue;
524219b2ee8SDavid du Colombier lock(pt);
525219b2ee8SDavid du Colombier ref = --pt->ref;
526219b2ee8SDavid du Colombier unlock(pt);
527219b2ee8SDavid du Colombier if(ref == 0)
528219b2ee8SDavid du Colombier free(pt);
529219b2ee8SDavid du Colombier }
530219b2ee8SDavid du Colombier break;
5313e12c5d1SDavid du Colombier default:
5323e12c5d1SDavid du Colombier for(pg = p->first; pg <= p->last; pg++)
5333e12c5d1SDavid du Colombier if(*pg) {
5343e12c5d1SDavid du Colombier putpage(*pg);
5353e12c5d1SDavid du Colombier *pg = 0;
5363e12c5d1SDavid du Colombier }
5373e12c5d1SDavid du Colombier }
5383e12c5d1SDavid du Colombier free(p);
5393e12c5d1SDavid du Colombier }
540ea15f0ccSDavid du Colombier
541ea15f0ccSDavid du Colombier ulong
pagenumber(Page * p)542ea15f0ccSDavid du Colombier pagenumber(Page *p)
543ea15f0ccSDavid du Colombier {
544ea15f0ccSDavid du Colombier return p-palloc.pages;
545ea15f0ccSDavid du Colombier }
546ea15f0ccSDavid du Colombier
547ea15f0ccSDavid du Colombier void
checkpagerefs(void)548ea15f0ccSDavid du Colombier checkpagerefs(void)
549ea15f0ccSDavid du Colombier {
550ea15f0ccSDavid du Colombier int s;
551ea15f0ccSDavid du Colombier ulong i, np, nwrong;
552ea15f0ccSDavid du Colombier ulong *ref;
553ea15f0ccSDavid du Colombier
554ea15f0ccSDavid du Colombier np = palloc.user;
555ea15f0ccSDavid du Colombier ref = malloc(np*sizeof ref[0]);
556ea15f0ccSDavid du Colombier if(ref == nil){
557ea15f0ccSDavid du Colombier print("checkpagerefs: out of memory\n");
558ea15f0ccSDavid du Colombier return;
559ea15f0ccSDavid du Colombier }
560ea15f0ccSDavid du Colombier
561ea15f0ccSDavid du Colombier /*
562ea15f0ccSDavid du Colombier * This may not be exact if there are other processes
563ea15f0ccSDavid du Colombier * holding refs to pages on their stacks. The hope is
564ea15f0ccSDavid du Colombier * that if you run it on a quiescent system it will still
565ea15f0ccSDavid du Colombier * be useful.
566ea15f0ccSDavid du Colombier */
567ea15f0ccSDavid du Colombier s = splhi();
568ea15f0ccSDavid du Colombier lock(&palloc);
569ea15f0ccSDavid du Colombier countpagerefs(ref, 0);
570ea15f0ccSDavid du Colombier portcountpagerefs(ref, 0);
571ea15f0ccSDavid du Colombier nwrong = 0;
572ea15f0ccSDavid du Colombier for(i=0; i<np; i++){
573ea15f0ccSDavid du Colombier if(palloc.pages[i].ref != ref[i]){
574ea15f0ccSDavid du Colombier iprint("page %#.8lux ref %d actual %lud\n",
575ea15f0ccSDavid du Colombier palloc.pages[i].pa, palloc.pages[i].ref, ref[i]);
576ea15f0ccSDavid du Colombier ref[i] = 1;
577ea15f0ccSDavid du Colombier nwrong++;
578ea15f0ccSDavid du Colombier }else
579ea15f0ccSDavid du Colombier ref[i] = 0;
580ea15f0ccSDavid du Colombier }
581ea15f0ccSDavid du Colombier countpagerefs(ref, 1);
582ea15f0ccSDavid du Colombier portcountpagerefs(ref, 1);
583ea15f0ccSDavid du Colombier iprint("%lud mistakes found\n", nwrong);
584ea15f0ccSDavid du Colombier unlock(&palloc);
585ea15f0ccSDavid du Colombier splx(s);
586ea15f0ccSDavid du Colombier }
587ea15f0ccSDavid du Colombier
588ea15f0ccSDavid du Colombier void
portcountpagerefs(ulong * ref,int print)589ea15f0ccSDavid du Colombier portcountpagerefs(ulong *ref, int print)
590ea15f0ccSDavid du Colombier {
591ea15f0ccSDavid du Colombier ulong i, j, k, ns, n;
592ea15f0ccSDavid du Colombier Page **pg, *entry;
593ea15f0ccSDavid du Colombier Proc *p;
594ea15f0ccSDavid du Colombier Pte *pte;
595ea15f0ccSDavid du Colombier Segment *s;
596ea15f0ccSDavid du Colombier
597ea15f0ccSDavid du Colombier /*
598ea15f0ccSDavid du Colombier * Pages in segments. s->mark avoids double-counting.
599ea15f0ccSDavid du Colombier */
600ea15f0ccSDavid du Colombier n = 0;
601ea15f0ccSDavid du Colombier ns = 0;
602ea15f0ccSDavid du Colombier for(i=0; i<conf.nproc; i++){
603ea15f0ccSDavid du Colombier p = proctab(i);
604ea15f0ccSDavid du Colombier for(j=0; j<NSEG; j++){
605ea15f0ccSDavid du Colombier s = p->seg[j];
606ea15f0ccSDavid du Colombier if(s)
607ea15f0ccSDavid du Colombier s->mark = 0;
608ea15f0ccSDavid du Colombier }
609ea15f0ccSDavid du Colombier }
610ea15f0ccSDavid du Colombier for(i=0; i<conf.nproc; i++){
611ea15f0ccSDavid du Colombier p = proctab(i);
612ea15f0ccSDavid du Colombier for(j=0; j<NSEG; j++){
613ea15f0ccSDavid du Colombier s = p->seg[j];
614ea15f0ccSDavid du Colombier if(s == nil || s->mark++)
615ea15f0ccSDavid du Colombier continue;
616ea15f0ccSDavid du Colombier ns++;
617ea15f0ccSDavid du Colombier for(k=0; k<s->mapsize; k++){
618ea15f0ccSDavid du Colombier pte = s->map[k];
619ea15f0ccSDavid du Colombier if(pte == nil)
620ea15f0ccSDavid du Colombier continue;
621ea15f0ccSDavid du Colombier for(pg = pte->first; pg <= pte->last; pg++){
622ea15f0ccSDavid du Colombier entry = *pg;
623ea15f0ccSDavid du Colombier if(pagedout(entry))
624ea15f0ccSDavid du Colombier continue;
625ea15f0ccSDavid du Colombier if(print){
626ea15f0ccSDavid du Colombier if(ref[pagenumber(entry)])
627ea15f0ccSDavid du Colombier iprint("page %#.8lux in segment %#p\n", entry->pa, s);
628ea15f0ccSDavid du Colombier continue;
629ea15f0ccSDavid du Colombier }
630ea15f0ccSDavid du Colombier if(ref[pagenumber(entry)]++ == 0)
631ea15f0ccSDavid du Colombier n++;
632ea15f0ccSDavid du Colombier }
633ea15f0ccSDavid du Colombier }
634ea15f0ccSDavid du Colombier }
635ea15f0ccSDavid du Colombier }
636ea15f0ccSDavid du Colombier if(!print){
637ea15f0ccSDavid du Colombier iprint("%lud pages in %lud segments\n", n, ns);
638ea15f0ccSDavid du Colombier for(i=0; i<conf.nproc; i++){
639ea15f0ccSDavid du Colombier p = proctab(i);
640ea15f0ccSDavid du Colombier for(j=0; j<NSEG; j++){
641ea15f0ccSDavid du Colombier s = p->seg[j];
642ea15f0ccSDavid du Colombier if(s == nil)
643ea15f0ccSDavid du Colombier continue;
644ea15f0ccSDavid du Colombier if(s->ref != s->mark){
645567483c8SDavid du Colombier iprint("segment %#p (used by proc %lud pid %lud) has bad ref count %lud actual %lud\n",
646ea15f0ccSDavid du Colombier s, i, p->pid, s->ref, s->mark);
647ea15f0ccSDavid du Colombier }
648ea15f0ccSDavid du Colombier }
649ea15f0ccSDavid du Colombier }
650ea15f0ccSDavid du Colombier }
651ea15f0ccSDavid du Colombier }
652ea15f0ccSDavid du Colombier
653