vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

page.c (11260B)


      1 #include	"u.h"
      2 #include	"lib.h"
      3 #include	"mem.h"
      4 #include	"dat.h"
      5 #include	"fns.h"
      6 #include	"error.h"
      7 
      8 #define	pghash(daddr)	palloc.hash[(daddr>>PGSHIFT)&(PGHSIZE-1)]
      9 
     10 struct	Palloc palloc;
     11 
     12 void
     13 pageinit(void)
     14 {
     15 	int color, i, j;
     16 	Page *p;
     17 	Pallocmem *pm;
     18 	ulong m, np, k, vkb, pkb;
     19 
     20 	np = 0;
     21 	for(i=0; i<nelem(palloc.mem); i++){
     22 		pm = &palloc.mem[i];
     23 		np += pm->npage;
     24 	}
     25 	palloc.pages = xalloc(np*sizeof(Page));
     26 	if(palloc.pages == 0)
     27 		panic("pageinit");
     28 
     29 	color = 0;
     30 	palloc.head = palloc.pages;
     31 	p = palloc.head;
     32 	for(i=0; i<nelem(palloc.mem); i++){
     33 		pm = &palloc.mem[i];
     34 		for(j=0; j<pm->npage; j++){
     35 			p->prev = p-1;
     36 			p->next = p+1;
     37 			p->pa = pm->base+j*BY2PG;
     38 			p->color = color;
     39 			palloc.freecount++;
     40 			color = (color+1)%NCOLOR;
     41 			p++;
     42 		}
     43 	}
     44 	palloc.tail = p - 1;
     45 	palloc.head->prev = 0;
     46 	palloc.tail->next = 0;
     47 
     48 	palloc.user = p - palloc.pages;
     49 	pkb = palloc.user*BY2PG/1024;
     50 	vkb = pkb + (conf.nswap*BY2PG)/1024;
     51 
     52 	/* Paging numbers */
     53 	swapalloc.highwater = (palloc.user*5)/100;
     54 	swapalloc.headroom = swapalloc.highwater + (swapalloc.highwater/4);
     55 
     56 	m = 0;
     57 	for(i=0; i<nelem(conf.mem); i++)
     58 		if(conf.mem[i].npage)
     59 			m += conf.mem[i].npage*BY2PG;
     60 	k = 0;
     61 	print("%ldM memory: ", (m+k+1024*1024-1)/(1024*1024));
     62 	print("%ldM kernel data, ", (m+k-pkb*1024+1024*1024-1)/(1024*1024));
     63 	print("%ldM user, ", pkb/1024);
     64 	print("%ldM swap\n", vkb/1024);
     65 }
     66 
     67 static void
     68 pageunchain(Page *p)
     69 {
     70 	if(canlock(&palloc.lk))
     71 		panic("pageunchain (palloc %p)", &palloc);
     72 	if(p->prev)
     73 		p->prev->next = p->next;
     74 	else
     75 		palloc.head = p->next;
     76 	if(p->next)
     77 		p->next->prev = p->prev;
     78 	else
     79 		palloc.tail = p->prev;
     80 	p->prev = p->next = nil;
     81 	palloc.freecount--;
     82 }
     83 
     84 void
     85 pagechaintail(Page *p)
     86 {
     87 	if(canlock(&palloc.lk))
     88 		panic("pagechaintail");
     89 	if(palloc.tail) {
     90 		p->prev = palloc.tail;
     91 		palloc.tail->next = p;
     92 	}
     93 	else {
     94 		palloc.head = p;
     95 		p->prev = 0;
     96 	}
     97 	palloc.tail = p;
     98 	p->next = 0;
     99 	palloc.freecount++;
    100 }
    101 
    102 void
    103 pagechainhead(Page *p)
    104 {
    105 	if(canlock(&palloc.lk))
    106 		panic("pagechainhead");
    107 	if(palloc.head) {
    108 		p->next = palloc.head;
    109 		palloc.head->prev = p;
    110 	}
    111 	else {
    112 		palloc.tail = p;
    113 		p->next = 0;
    114 	}
    115 	palloc.head = p;
    116 	p->prev = 0;
    117 	palloc.freecount++;
    118 }
    119 
    120 Page*
    121 newpage(int clear, Segment **s, ulong va)
    122 {
    123 	Page *p;
    124 	KMap *k;
    125 	uchar ct;
    126 	int hw, dontalloc, color;
    127 
    128 	lock(&palloc.lk);
    129 	color = getpgcolor(va);
    130 	hw = swapalloc.highwater;
    131 	for(;;) {
    132 		if(palloc.freecount > hw)
    133 			break;
    134 		if(up->kp && palloc.freecount > 0)
    135 			break;
    136 
    137 		unlock(&palloc.lk);
    138 		dontalloc = 0;
    139 		if(s && *s) {
    140 			qunlock(&((*s)->lk));
    141 			*s = 0;
    142 			dontalloc = 1;
    143 		}
    144 		qlock(&palloc.pwait);	/* Hold memory requesters here */
    145 
    146 		while(waserror())	/* Ignore interrupts */
    147 			;
    148 
    149 		kickpager();
    150 		tsleep(&palloc.r, ispages, 0, 1000);
    151 
    152 		poperror();
    153 
    154 		qunlock(&palloc.pwait);
    155 
    156 		/*
    157 		 * If called from fault and we lost the segment from
    158 		 * underneath don't waste time allocating and freeing
    159 		 * a page. Fault will call newpage again when it has
    160 		 * reacquired the segment locks
    161 		 */
    162 		if(dontalloc)
    163 			return 0;
    164 
    165 		lock(&palloc.lk);
    166 	}
    167 
    168 	/* First try for our colour */
    169 	for(p = palloc.head; p; p = p->next)
    170 		if(p->color == color)
    171 			break;
    172 
    173 	ct = PG_NOFLUSH;
    174 	if(p == 0) {
    175 		p = palloc.head;
    176 		p->color = color;
    177 		ct = PG_NEWCOL;
    178 	}
    179 	(void)ct;
    180 
    181 	pageunchain(p);
    182 
    183 	lock(&p->lk);
    184 	if(p->ref != 0)
    185 		panic("newpage: p->ref %d != 0", p->ref);
    186 
    187 	uncachepage(p);
    188 	p->ref++;
    189 	p->va = va;
    190 	p->modref = 0;
    191 	unlock(&p->lk);
    192 	unlock(&palloc.lk);
    193 
    194 	if(clear) {
    195 		k = kmap(p);
    196 		memset((void*)VA(k), 0, BY2PG);
    197 		kunmap(k);
    198 	}
    199 
    200 	return p;
    201 }
    202 
    203 int
    204 ispages(void *v)
    205 {
    206 	return palloc.freecount >= swapalloc.highwater;
    207 }
    208 
    209 void
    210 putpage(Page *p)
    211 {
    212 	if(onswap(p)) {
    213 		putswap(p);
    214 		return;
    215 	}
    216 
    217 	lock(&palloc.lk);
    218 	lock(&p->lk);
    219 
    220 	if(p->ref == 0)
    221 		panic("putpage");
    222 
    223 	if(--p->ref > 0) {
    224 		unlock(&p->lk);
    225 		unlock(&palloc.lk);
    226 		return;
    227 	}
    228 
    229 	if(p->image && p->image != &swapimage)
    230 		pagechaintail(p);
    231 	else 
    232 		pagechainhead(p);
    233 
    234 	if(palloc.r.p != 0)
    235 		wakeup(&palloc.r);
    236 
    237 	unlock(&p->lk);
    238 	unlock(&palloc.lk);
    239 }
    240 
    241 Page*
    242 auxpage(void)
    243 {
    244 	Page *p;
    245 
    246 	lock(&palloc.lk);
    247 	p = palloc.head;
    248 	if(palloc.freecount < swapalloc.highwater) {
    249 		unlock(&palloc.lk);
    250 		return 0;
    251 	}
    252 	pageunchain(p);
    253 
    254 	lock(&p->lk);
    255 	if(p->ref != 0)
    256 		panic("auxpage");
    257 	p->ref++;
    258 	uncachepage(p);
    259 	unlock(&p->lk);
    260 	unlock(&palloc.lk);
    261 
    262 	return p;
    263 }
    264 
    265 static int dupretries = 15000;
    266 
    267 int
    268 duppage(Page *p)				/* Always call with p locked */
    269 {
    270 	Page *np;
    271 	int color;
    272 	int retries;
    273 
    274 	retries = 0;
    275 retry:
    276 
    277 	if(retries++ > dupretries){
    278 		print("duppage %d, up %p\n", retries, up);
    279 		dupretries += 100;
    280 		if(dupretries > 100000)
    281 			panic("duppage\n");
    282 		uncachepage(p);
    283 		return 1;
    284 	}
    285 		
    286 
    287 	/* don't dup pages with no image */
    288 	if(p->ref == 0 || p->image == nil || p->image->notext)
    289 		return 0;
    290 
    291 	/*
    292 	 *  normal lock ordering is to call
    293 	 *  lock(&palloc.lk) before lock(&p->lk).
    294 	 *  To avoid deadlock, we have to drop
    295 	 *  our locks and try again.
    296 	 */
    297 	if(!canlock(&palloc.lk)){
    298 		unlock(&p->lk);
    299 		if(up)
    300 			sched();
    301 		lock(&p->lk);
    302 		goto retry;
    303 	}
    304 
    305 	/* No freelist cache when memory is very low */
    306 	if(palloc.freecount < swapalloc.highwater) {
    307 		unlock(&palloc.lk);
    308 		uncachepage(p);
    309 		return 1;
    310 	}
    311 
    312 	color = getpgcolor(p->va);
    313 	for(np = palloc.head; np; np = np->next)
    314 		if(np->color == color)
    315 			break;
    316 
    317 	/* No page of the correct color */
    318 	if(np == 0) {
    319 		unlock(&palloc.lk);
    320 		uncachepage(p);
    321 		return 1;
    322 	}
    323 
    324 	pageunchain(np);
    325 	pagechaintail(np);
    326 /*
    327 * XXX - here's a bug? - np is on the freelist but it's not really free.
    328 * when we unlock palloc someone else can come in, decide to
    329 * use np, and then try to lock it.  they succeed after we've 
    330 * run copypage and cachepage and unlock(&np->lk).  then what?
    331 * they call pageunchain before locking(np), so it's removed
    332 * from the freelist, but still in the cache because of
    333 * cachepage below.  if someone else looks in the cache
    334 * before they remove it, the page will have a nonzero ref
    335 * once they finally lock(&np->lk).
    336 */
    337 	lock(&np->lk);
    338 	unlock(&palloc.lk);
    339 
    340 	/* Cache the new version */
    341 	uncachepage(np);
    342 	np->va = p->va;
    343 	np->daddr = p->daddr;
    344 	copypage(p, np);
    345 	cachepage(np, p->image);
    346 	unlock(&np->lk);
    347 	uncachepage(p);
    348 
    349 	return 0;
    350 }
    351 
    352 void
    353 copypage(Page *f, Page *t)
    354 {
    355 	KMap *ks, *kd;
    356 
    357 	ks = kmap(f);
    358 	kd = kmap(t);
    359 	memmove((void*)VA(kd), (void*)VA(ks), BY2PG);
    360 	kunmap(ks);
    361 	kunmap(kd);
    362 }
    363 
    364 void
    365 uncachepage(Page *p)			/* Always called with a locked page */
    366 {
    367 	Page **l, *f;
    368 
    369 	if(p->image == 0)
    370 		return;
    371 
    372 	lock(&palloc.hashlock);
    373 	l = &pghash(p->daddr);
    374 	for(f = *l; f; f = f->hash) {
    375 		if(f == p) {
    376 			*l = p->hash;
    377 			break;
    378 		}
    379 		l = &f->hash;
    380 	}
    381 	unlock(&palloc.hashlock);
    382 	putimage(p->image);
    383 	p->image = 0;
    384 	p->daddr = 0;
    385 }
    386 
    387 void
    388 cachepage(Page *p, Image *i)
    389 {
    390 	Page **l;
    391 
    392 	/* If this ever happens it should be fixed by calling
    393 	 * uncachepage instead of panic. I think there is a race
    394 	 * with pio in which this can happen. Calling uncachepage is
    395 	 * correct - I just wanted to see if we got here.
    396 	 */
    397 	if(p->image)
    398 		panic("cachepage");
    399 
    400 	incref(&i->ref);
    401 	lock(&palloc.hashlock);
    402 	p->image = i;
    403 	l = &pghash(p->daddr);
    404 	p->hash = *l;
    405 	*l = p;
    406 	unlock(&palloc.hashlock);
    407 }
    408 
    409 void
    410 cachedel(Image *i, ulong daddr)
    411 {
    412 	Page *f, **l;
    413 
    414 	lock(&palloc.hashlock);
    415 	l = &pghash(daddr);
    416 	for(f = *l; f; f = f->hash) {
    417 		if(f->image == i && f->daddr == daddr) {
    418 			lock(&f->lk);
    419 			if(f->image == i && f->daddr == daddr){
    420 				*l = f->hash;
    421 				putimage(f->image);
    422 				f->image = 0;
    423 				f->daddr = 0;
    424 			}
    425 			unlock(&f->lk);
    426 			break;
    427 		}
    428 		l = &f->hash;
    429 	}
    430 	unlock(&palloc.hashlock);
    431 }
    432 
    433 Page *
    434 lookpage(Image *i, ulong daddr)
    435 {
    436 	Page *f;
    437 
    438 	lock(&palloc.hashlock);
    439 	for(f = pghash(daddr); f; f = f->hash) {
    440 		if(f->image == i && f->daddr == daddr) {
    441 			unlock(&palloc.hashlock);
    442 
    443 			lock(&palloc.lk);
    444 			lock(&f->lk);
    445 			if(f->image != i || f->daddr != daddr) {
    446 				unlock(&f->lk);
    447 				unlock(&palloc.lk);
    448 				return 0;
    449 			}
    450 			if(++f->ref == 1)
    451 				pageunchain(f);
    452 			unlock(&palloc.lk);
    453 			unlock(&f->lk);
    454 
    455 			return f;
    456 		}
    457 	}
    458 	unlock(&palloc.hashlock);
    459 
    460 	return 0;
    461 }
    462 
    463 Pte*
    464 ptecpy(Pte *old)
    465 {
    466 	Pte *new;
    467 	Page **src, **dst;
    468 
    469 	new = ptealloc();
    470 	dst = &new->pages[old->first-old->pages];
    471 	new->first = dst;
    472 	for(src = old->first; src <= old->last; src++, dst++)
    473 		if(*src) {
    474 			if(onswap(*src))
    475 				dupswap(*src);
    476 			else {
    477 				lock(&(*src)->lk);
    478 				(*src)->ref++;
    479 				unlock(&(*src)->lk);
    480 			}
    481 			new->last = dst;
    482 			*dst = *src;
    483 		}
    484 
    485 	return new;
    486 }
    487 
    488 Pte*
    489 ptealloc(void)
    490 {
    491 	Pte *new;
    492 
    493 	new = smalloc(sizeof(Pte));
    494 	new->first = &new->pages[PTEPERTAB];
    495 	new->last = new->pages;
    496 	return new;
    497 }
    498 
    499 void
    500 freepte(Segment *s, Pte *p)
    501 {
    502 	int ref;
    503 	void (*fn)(Page*);
    504 	Page *pt, **pg, **ptop;
    505 
    506 	switch(s->type&SG_TYPE) {
    507 	case SG_PHYSICAL:
    508 		fn = s->pseg->pgfree;
    509 		ptop = &p->pages[PTEPERTAB];
    510 		if(fn) {
    511 			for(pg = p->pages; pg < ptop; pg++) {
    512 				if(*pg == 0)
    513 					continue;
    514 				(*fn)(*pg);
    515 				*pg = 0;
    516 			}
    517 			break;
    518 		}
    519 		for(pg = p->pages; pg < ptop; pg++) {
    520 			pt = *pg;
    521 			if(pt == 0)
    522 				continue;
    523 			lock(&pt->lk);
    524 			ref = --pt->ref;
    525 			unlock(&pt->lk);
    526 			if(ref == 0)
    527 				free(pt);
    528 		}
    529 		break;
    530 	default:
    531 		for(pg = p->first; pg <= p->last; pg++)
    532 			if(*pg) {
    533 				putpage(*pg);
    534 				*pg = 0;
    535 			}
    536 	}
    537 	free(p);
    538 }
    539 
    540 ulong
    541 pagenumber(Page *p)
    542 {
    543 	return p-palloc.pages;
    544 }
    545 
    546 void
    547 checkpagerefs(void)
    548 {
    549 	int s;
    550 	ulong i, np, nwrong;
    551 	ulong *ref;
    552 	
    553 	np = palloc.user;
    554 	ref = malloc(np*sizeof ref[0]);
    555 	if(ref == nil){
    556 		print("checkpagerefs: out of memory\n");
    557 		return;
    558 	}
    559 	
    560 	/*
    561 	 * This may not be exact if there are other processes
    562 	 * holding refs to pages on their stacks.  The hope is
    563 	 * that if you run it on a quiescent system it will still
    564 	 * be useful.
    565 	 */
    566 	s = splhi();
    567 	lock(&palloc.lk);
    568 	countpagerefs(ref, 0);
    569 	portcountpagerefs(ref, 0);
    570 	nwrong = 0;
    571 	for(i=0; i<np; i++){
    572 		if(palloc.pages[i].ref != ref[i]){
    573 			iprint("page %#.8lux ref %d actual %lud\n", 
    574 				palloc.pages[i].pa, palloc.pages[i].ref, ref[i]);
    575 			ref[i] = 1;
    576 			nwrong++;
    577 		}else
    578 			ref[i] = 0;
    579 	}
    580 	countpagerefs(ref, 1);
    581 	portcountpagerefs(ref, 1);
    582 	iprint("%lud mistakes found\n", nwrong);
    583 	unlock(&palloc.lk);
    584 	splx(s);
    585 }
    586 
    587 void
    588 portcountpagerefs(ulong *ref, int print)
    589 {
    590 	ulong i, j, k, ns, n;
    591 	Page **pg, *entry;
    592 	Proc *p;
    593 	Pte *pte;
    594 	Segment *s;
    595 
    596 	/*
    597 	 * Pages in segments.  s->mark avoids double-counting.
    598 	 */
    599 	n = 0;
    600 	ns = 0;
    601 	for(i=0; i<conf.nproc; i++){
    602 		p = proctab(i);
    603 		for(j=0; j<NSEG; j++){
    604 			s = p->seg[j];
    605 			if(s)
    606 				s->mark = 0;
    607 		}
    608 	}
    609 	for(i=0; i<conf.nproc; i++){
    610 		p = proctab(i);
    611 		for(j=0; j<NSEG; j++){
    612 			s = p->seg[j];
    613 			if(s == nil || s->mark++)
    614 				continue;
    615 			ns++;
    616 			for(k=0; k<s->mapsize; k++){
    617 				pte = s->map[k];
    618 				if(pte == nil)
    619 					continue;
    620 				for(pg = pte->first; pg <= pte->last; pg++){
    621 					entry = *pg;
    622 					if(pagedout(entry))
    623 						continue;
    624 					if(print){
    625 						if(ref[pagenumber(entry)])
    626 							iprint("page %#.8lux in segment %#p\n", entry->pa, s);
    627 						continue;
    628 					}
    629 					if(ref[pagenumber(entry)]++ == 0)
    630 						n++;
    631 				}
    632 			}
    633 		}
    634 	}
    635 	if(!print){
    636 		iprint("%lud pages in %lud segments\n", n, ns);
    637 		for(i=0; i<conf.nproc; i++){
    638 			p = proctab(i);
    639 			for(j=0; j<NSEG; j++){
    640 				s = p->seg[j];
    641 				if(s == nil)
    642 					continue;
    643 				if(s->ref.ref != s->mark){
    644 					iprint("segment %#p (used by proc %lud pid %lud) has bad ref count %lud actual %lud\n",
    645 						s, i, p->pid, s->ref, s->mark);
    646 				}
    647 			}
    648 		}
    649 	}
    650 }
    651