xref: /plan9/sys/src/9/port/page.c (revision c6569576083e48cef148efbb162a33bacec4ce98)
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