FreeBSD/Linux Kernel Cross Reference
sys/port/page.c
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");
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
Cache object: 5f52c630c5503fc2593b0fc48a3ecf4c
|