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