Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/9/port/page.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"../port/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 = PGROUND(end - (char*)KTZERO);
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))
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))
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))
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 i, hw, dontalloc, color;
127
 
128
	lock(&palloc);
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);
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);
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
 
180
	pageunchain(p);
181
 
182
	lock(p);
183
	if(p->ref != 0)
184
		panic("newpage: p->ref %d != 0", p->ref);
185
 
186
	uncachepage(p);
187
	p->ref++;
188
	p->va = va;
189
	p->modref = 0;
190
	for(i = 0; i < MAXMACH; i++)
191
		p->cachectl[i] = ct;
192
	unlock(p);
193
	unlock(&palloc);
194
 
195
	if(clear) {
196
		k = kmap(p);
197
		memset((void*)VA(k), 0, BY2PG);
198
		kunmap(k);
199
	}
200
 
201
	return p;
202
}
203
 
204
int
205
ispages(void*)
206
{
207
	return palloc.freecount >= swapalloc.highwater;
208
}
209
 
210
void
211
putpage(Page *p)
212
{
213
	if(onswap(p)) {
214
		putswap(p);
215
		return;
216
	}
217
 
218
	lock(&palloc);
219
	lock(p);
220
 
221
	if(p->ref == 0)
222
		panic("putpage");
223
 
224
	if(--p->ref > 0) {
225
		unlock(p);
226
		unlock(&palloc);
227
		return;
228
	}
229
 
230
	if(p->image && p->image != &swapimage)
231
		pagechaintail(p);
232
	else 
233
		pagechainhead(p);
234
 
235
	if(palloc.r.p != 0)
236
		wakeup(&palloc.r);
237
 
238
	unlock(p);
239
	unlock(&palloc);
240
}
241
 
242
Page*
243
auxpage(void)
244
{
245
	Page *p;
246
 
247
	lock(&palloc);
248
	p = palloc.head;
249
	if(palloc.freecount < swapalloc.highwater) {
250
		unlock(&palloc);
251
		return 0;
252
	}
253
	pageunchain(p);
254
 
255
	lock(p);
256
	if(p->ref != 0)
257
		panic("auxpage");
258
	p->ref++;
259
	uncachepage(p);
260
	unlock(p);
261
	unlock(&palloc);
262
 
263
	return p;
264
}
265
 
266
static int dupretries = 15000;
267
 
268
int
269
duppage(Page *p)				/* Always call with p locked */
270
{
271
	Page *np;
272
	int color;
273
	int retries;
274
 
275
	retries = 0;
276
retry:
277
 
278
	if(retries++ > dupretries){
279
		print("duppage %d, up %p\n", retries, up);
280
		dupretries += 100;
281
		if(dupretries > 100000)
282
			panic("duppage\n");
283
		uncachepage(p);
284
		return 1;
285
	}
286
 
287
 
288
	/* don't dup pages with no image */
289
	if(p->ref == 0 || p->image == nil || p->image->notext)
290
		return 0;
291
 
292
	/*
293
	 *  normal lock ordering is to call
294
	 *  lock(&palloc) before lock(p).
295
	 *  To avoid deadlock, we have to drop
296
	 *  our locks and try again.
297
	 */
298
	if(!canlock(&palloc)){
299
		unlock(p);
300
		if(up)
301
			sched();
302
		lock(p);
303
		goto retry;
304
	}
305
 
306
	/* No freelist cache when memory is very low */
307
	if(palloc.freecount < swapalloc.highwater) {
308
		unlock(&palloc);
309
		uncachepage(p);
310
		return 1;
311
	}
312
 
313
	color = getpgcolor(p->va);
314
	for(np = palloc.head; np; np = np->next)
315
		if(np->color == color)
316
			break;
317
 
318
	/* No page of the correct color */
319
	if(np == 0) {
320
		unlock(&palloc);
321
		uncachepage(p);
322
		return 1;
323
	}
324
 
325
	pageunchain(np);
326
	pagechaintail(np);
327
/*
328
* XXX - here's a bug? - np is on the freelist but it's not really free.
329
* when we unlock palloc someone else can come in, decide to
330
* use np, and then try to lock it.  they succeed after we've 
331
* run copypage and cachepage and unlock(np).  then what?
332
* they call pageunchain before locking(np), so it's removed
333
* from the freelist, but still in the cache because of
334
* cachepage below.  if someone else looks in the cache
335
* before they remove it, the page will have a nonzero ref
336
* once they finally lock(np).
337
*/
338
	lock(np);
339
	unlock(&palloc);
340
 
341
	/* Cache the new version */
342
	uncachepage(np);
343
	np->va = p->va;
344
	np->daddr = p->daddr;
345
	copypage(p, np);
346
	cachepage(np, p->image);
347
	unlock(np);
348
	uncachepage(p);
349
 
350
	return 0;
351
}
352
 
353
void
354
copypage(Page *f, Page *t)
355
{
356
	KMap *ks, *kd;
357
 
358
	ks = kmap(f);
359
	kd = kmap(t);
360
	memmove((void*)VA(kd), (void*)VA(ks), BY2PG);
361
	kunmap(ks);
362
	kunmap(kd);
363
}
364
 
365
void
366
uncachepage(Page *p)			/* Always called with a locked page */
367
{
368
	Page **l, *f;
369
 
370
	if(p->image == 0)
371
		return;
372
 
373
	lock(&palloc.hashlock);
374
	l = &pghash(p->daddr);
375
	for(f = *l; f; f = f->hash) {
376
		if(f == p) {
377
			*l = p->hash;
378
			break;
379
		}
380
		l = &f->hash;
381
	}
382
	unlock(&palloc.hashlock);
383
	putimage(p->image);
384
	p->image = 0;
385
	p->daddr = 0;
386
}
387
 
388
void
389
cachepage(Page *p, Image *i)
390
{
391
	Page **l;
392
 
393
	/* If this ever happens it should be fixed by calling
394
	 * uncachepage instead of panic. I think there is a race
395
	 * with pio in which this can happen. Calling uncachepage is
396
	 * correct - I just wanted to see if we got here.
397
	 */
398
	if(p->image)
399
		panic("cachepage");
400
 
401
	incref(i);
402
	lock(&palloc.hashlock);
403
	p->image = i;
404
	l = &pghash(p->daddr);
405
	p->hash = *l;
406
	*l = p;
407
	unlock(&palloc.hashlock);
408
}
409
 
410
void
411
cachedel(Image *i, ulong daddr)
412
{
413
	Page *f, **l;
414
 
415
	lock(&palloc.hashlock);
416
	l = &pghash(daddr);
417
	for(f = *l; f; f = f->hash) {
418
		if(f->image == i && f->daddr == daddr) {
419
			lock(f);
420
			if(f->image == i && f->daddr == daddr){
421
				*l = f->hash;
422
				putimage(f->image);
423
				f->image = 0;
424
				f->daddr = 0;
425
			}
426
			unlock(f);
427
			break;
428
		}
429
		l = &f->hash;
430
	}
431
	unlock(&palloc.hashlock);
432
}
433
 
434
Page *
435
lookpage(Image *i, ulong daddr)
436
{
437
	Page *f;
438
 
439
	lock(&palloc.hashlock);
440
	for(f = pghash(daddr); f; f = f->hash) {
441
		if(f->image == i && f->daddr == daddr) {
442
			unlock(&palloc.hashlock);
443
 
444
			lock(&palloc);
445
			lock(f);
446
			if(f->image != i || f->daddr != daddr) {
447
				unlock(f);
448
				unlock(&palloc);
449
				return 0;
450
			}
451
			if(++f->ref == 1)
452
				pageunchain(f);
453
			unlock(&palloc);
454
			unlock(f);
455
 
456
			return f;
457
		}
458
	}
459
	unlock(&palloc.hashlock);
460
 
461
	return 0;
462
}
463
 
464
Pte*
465
ptecpy(Pte *old)
466
{
467
	Pte *new;
468
	Page **src, **dst;
469
 
470
	new = ptealloc();
471
	dst = &new->pages[old->first-old->pages];
472
	new->first = dst;
473
	for(src = old->first; src <= old->last; src++, dst++)
474
		if(*src) {
475
			if(onswap(*src))
476
				dupswap(*src);
477
			else {
478
				lock(*src);
479
				(*src)->ref++;
480
				unlock(*src);
481
			}
482
			new->last = dst;
483
			*dst = *src;
484
		}
485
 
486
	return new;
487
}
488
 
489
Pte*
490
ptealloc(void)
491
{
492
	Pte *new;
493
 
494
	new = smalloc(sizeof(Pte));
495
	new->first = &new->pages[PTEPERTAB];
496
	new->last = new->pages;
497
	return new;
498
}
499
 
500
void
501
freepte(Segment *s, Pte *p)
502
{
503
	int ref;
504
	void (*fn)(Page*);
505
	Page *pt, **pg, **ptop;
506
 
507
	switch(s->type&SG_TYPE) {
508
	case SG_PHYSICAL:
509
		fn = s->pseg->pgfree;
510
		ptop = &p->pages[PTEPERTAB];
511
		if(fn) {
512
			for(pg = p->pages; pg < ptop; pg++) {
513
				if(*pg == 0)
514
					continue;
515
				(*fn)(*pg);
516
				*pg = 0;
517
			}
518
			break;
519
		}
520
		for(pg = p->pages; pg < ptop; pg++) {
521
			pt = *pg;
522
			if(pt == 0)
523
				continue;
524
			lock(pt);
525
			ref = --pt->ref;
526
			unlock(pt);
527
			if(ref == 0)
528
				free(pt);
529
		}
530
		break;
531
	default:
532
		for(pg = p->first; pg <= p->last; pg++)
533
			if(*pg) {
534
				putpage(*pg);
535
				*pg = 0;
536
			}
537
	}
538
	free(p);
539
}
540
 
541
ulong
542
pagenumber(Page *p)
543
{
544
	return p-palloc.pages;
545
}
546
 
547
void
548
checkpagerefs(void)
549
{
550
	int s;
551
	ulong i, np, nwrong;
552
	ulong *ref;
553
 
554
	np = palloc.user;
555
	ref = malloc(np*sizeof ref[0]);
556
	if(ref == nil){
557
		print("checkpagerefs: out of memory\n");
558
		return;
559
	}
560
 
561
	/*
562
	 * This may not be exact if there are other processes
563
	 * holding refs to pages on their stacks.  The hope is
564
	 * that if you run it on a quiescent system it will still
565
	 * be useful.
566
	 */
567
	s = splhi();
568
	lock(&palloc);
569
	countpagerefs(ref, 0);
570
	portcountpagerefs(ref, 0);
571
	nwrong = 0;
572
	for(i=0; i<np; i++){
573
		if(palloc.pages[i].ref != ref[i]){
574
			iprint("page %#.8lux ref %d actual %lud\n", 
575
				palloc.pages[i].pa, palloc.pages[i].ref, ref[i]);
576
			ref[i] = 1;
577
			nwrong++;
578
		}else
579
			ref[i] = 0;
580
	}
581
	countpagerefs(ref, 1);
582
	portcountpagerefs(ref, 1);
583
	iprint("%lud mistakes found\n", nwrong);
584
	unlock(&palloc);
585
	splx(s);
586
}
587
 
588
void
589
portcountpagerefs(ulong *ref, int print)
590
{
591
	ulong i, j, k, ns, n;
592
	Page **pg, *entry;
593
	Proc *p;
594
	Pte *pte;
595
	Segment *s;
596
 
597
	/*
598
	 * Pages in segments.  s->mark avoids double-counting.
599
	 */
600
	n = 0;
601
	ns = 0;
602
	for(i=0; i<conf.nproc; i++){
603
		p = proctab(i);
604
		for(j=0; j<NSEG; j++){
605
			s = p->seg[j];
606
			if(s)
607
				s->mark = 0;
608
		}
609
	}
610
	for(i=0; i<conf.nproc; i++){
611
		p = proctab(i);
612
		for(j=0; j<NSEG; j++){
613
			s = p->seg[j];
614
			if(s == nil || s->mark++)
615
				continue;
616
			ns++;
617
			for(k=0; k<s->mapsize; k++){
618
				pte = s->map[k];
619
				if(pte == nil)
620
					continue;
621
				for(pg = pte->first; pg <= pte->last; pg++){
622
					entry = *pg;
623
					if(pagedout(entry))
624
						continue;
625
					if(print){
626
						if(ref[pagenumber(entry)])
627
							iprint("page %#.8lux in segment %#p\n", entry->pa, s);
628
						continue;
629
					}
630
					if(ref[pagenumber(entry)]++ == 0)
631
						n++;
632
				}
633
			}
634
		}
635
	}
636
	if(!print){
637
		iprint("%lud pages in %lud segments\n", n, ns);
638
		for(i=0; i<conf.nproc; i++){
639
			p = proctab(i);
640
			for(j=0; j<NSEG; j++){
641
				s = p->seg[j];
642
				if(s == nil)
643
					continue;
644
				if(s->ref != s->mark){
645
					iprint("segment %#p (used by proc %lud pid %lud) has bad ref count %lud actual %lud\n",
646
						s, i, p->pid, s->ref, s->mark);
647
				}
648
			}
649
		}
650
	}
651
}
652