|
|
1.1 ! root 1: #include "sys/param.h" ! 2: #include "sys/systm.h" ! 3: #include "sys/inode.h" ! 4: #include "sys/user.h" ! 5: #include "sys/proc.h" ! 6: #include "sys/pte.h" ! 7: #include "sys/buf.h" ! 8: #include "sys/text.h" ! 9: #include "sys/mtpr.h" ! 10: #include "sys/cmap.h" ! 11: #include "sys/vm.h" ! 12: ! 13: struct pte *Pushmap; ! 14: struct user *pushutl; ! 15: ! 16: int nohash = 0; ! 17: /* ! 18: * Handle a page fault. ! 19: * ! 20: * Basic outline ! 21: * If page is allocated, but just not valid: ! 22: * Wait if intransit, else just revalidate ! 23: * Done ! 24: * Compute <dev,bn> from which page operation would take place ! 25: * If page is text page, and filling from file system or swap space: ! 26: * If in free list cache, reattach it and then done ! 27: * Allocate memory for page in ! 28: * If block here, restart because we could have swapped, etc. ! 29: * Lock process from swapping for duration ! 30: * Update pte's to reflect that page is intransit. ! 31: * If page is zero fill on demand: ! 32: * Clear pages and flush free list cache of stale cacheing ! 33: * for this swap page (e.g. before initializing again due ! 34: * to 407/410 exec). ! 35: * If page is fill from file and in buffer cache: ! 36: * Copy the page from the buffer cache. ! 37: * If not a fill on demand: ! 38: * Determine swap address and cluster to page in ! 39: * Do the swap to bring the page in ! 40: * Instrument the pagein ! 41: * After swap validate the required new page ! 42: * Leave prepaged pages reclaimable (not valid) ! 43: * Update shared copies of text page tables ! 44: * Complete bookkeeping on pages brought in: ! 45: * No longer intransit ! 46: * Hash text pages into core hash structure ! 47: * Unlock pages (modulo raw i/o requirements) ! 48: * Flush translation buffer ! 49: * Process pagein is done ! 50: */ ! 51: int preptofree = 1; /* send pre-paged pages to free list */ ! 52: static struct cmap dbcmap; /* debug */ ! 53: ! 54: pagein(virtaddr,uu) ! 55: caddr_t virtaddr; ! 56: register struct user *uu; ! 57: { ! 58: register struct proc *p; ! 59: register struct pte *pte; ! 60: register unsigned v; ! 61: unsigned pf; ! 62: int type, fileno, prot; ! 63: struct pte opte; ! 64: struct buf *bp; ! 65: dev_t dev; ! 66: register int i; ! 67: int klsize; ! 68: unsigned vsave; ! 69: struct cmap *c; ! 70: int j; ! 71: daddr_t bn, bncache, bnswap; ! 72: int otime, olbolt, oicr, a, s; ! 73: ! 74: s = spl6(); ! 75: otime = time, olbolt = lbolt, oicr = mfpr(ICR); ! 76: cnt.v_faults++; ! 77: /* ! 78: * Classify faulted page into a segment and get a pte ! 79: * for the faulted page. ! 80: */ ! 81: vsave = v = clbase(btop((unsigned int)virtaddr)); ! 82: p = uu->u_procp; ! 83: if (isatsv(p, v)) ! 84: type = CTEXT; ! 85: else if (isassv(p, v)) ! 86: type = CSTACK; ! 87: else ! 88: type = CDATA; ! 89: pte = vtopte(p, v); ! 90: if (pte->pg_v) ! 91: panic("pagein"); ! 92: ! 93: /* ! 94: * If page is reclaimable, reclaim it. ! 95: * If page is text and intransit, sleep while it is intransit, ! 96: * If it is valid after the sleep, we are done. ! 97: * Otherwise we have to start checking again, since page could ! 98: * even be reclaimable now (we may have swapped for a long time). ! 99: */ ! 100: restart: ! 101: if (pte->pg_fod == 0 && pte->pg_pfnum) { ! 102: if (type == CTEXT && cmap[pgtocm(pte->pg_pfnum)].c_intrans) { ! 103: sleep((caddr_t)p->p_textp, PSWP+1); ! 104: pte = vtopte(p, v); ! 105: if (pte->pg_v) { ! 106: valid: ! 107: if (p->p_flag & SDLYU) { ! 108: mlock(pte->pg_pfnum); ! 109: if (!pte->pg_v) { ! 110: munlock(pte->pg_pfnum); ! 111: goto restart; ! 112: } ! 113: } ! 114: tbiscl(v); ! 115: cnt.v_intrans++; ! 116: return; ! 117: } ! 118: goto restart; ! 119: } ! 120: /* ! 121: * If page is in the free list, then take ! 122: * it back into the resident set, updating ! 123: * the size recorded for the resident set. ! 124: */ ! 125: if (cmap[pgtocm(pte->pg_pfnum)].c_free) { ! 126: munlink(pte->pg_pfnum); ! 127: cnt.v_pgfrec++; ! 128: if (type == CTEXT) ! 129: p->p_textp->x_rssize += CLSIZE; ! 130: else ! 131: p->p_rssize += CLSIZE; ! 132: } ! 133: pte->pg_v = 1; ! 134: if (anycl(pte, pg_m)) ! 135: pte->pg_m = 1; ! 136: distcl(pte); ! 137: if (type == CTEXT) ! 138: distpte(p->p_textp, vtotp(p, v), pte); ! 139: if (p->p_flag & SDLYU) { ! 140: mlock(pte->pg_pfnum); ! 141: if (!pte->pg_v) { ! 142: munlock(pte->pg_pfnum); ! 143: goto restart; ! 144: } ! 145: } ! 146: uu->u_vm.vm_minflt++; ! 147: cnt.v_pgrec++; ! 148: tbiscl(v); ! 149: a = vmtime(otime, olbolt, oicr); ! 150: rectime += a; ! 151: if (a >= 0) ! 152: vmfltmon(rmon, a, rmonmin, rres, NRMON); ! 153: splx(s); ! 154: return; ! 155: } ! 156: splx(s); ! 157: /* ! 158: * <dev,bn> is where data comes from/goes to. ! 159: * <dev,bncache> is where data is cached from/to. ! 160: * <swapdev,bnswap> is where data will eventually go. ! 161: */ ! 162: if (pte->pg_fod == 0) { ! 163: fileno = -1; ! 164: bnswap = bncache = bn = dbtofsb(swapdev, ! 165: vtod(p, v, &uu->u_dmap, &uu->u_smap)); ! 166: dev = swapdev; ! 167: } else { ! 168: fileno = ((struct fpte *)pte)->pg_source; ! 169: bn = ((struct fpte *)pte)->pg_blkno; ! 170: bnswap = dbtofsb(swapdev, vtod(p, v, &uu->u_dmap, &uu->u_smap)); ! 171: if (fileno == PG_FTEXT) { ! 172: if (p->p_textp == 0) ! 173: panic("pagein PG_FTEXT"); ! 174: dev = p->p_textp->x_iptr->i_dev; ! 175: bncache = bn; ! 176: } else { /* PG_FZERO */ ! 177: dev = swapdev; ! 178: bncache = bnswap; ! 179: } ! 180: } ! 181: klsize = 1; ! 182: opte = *pte; ! 183: ! 184: /* ! 185: * Check for text detached but in free list. ! 186: * This can happen only if the page is filling ! 187: * from a inode or from the swap device, (e.g. not when reading ! 188: * in 407/410 execs to a zero fill page.) ! 189: * honour lock bit to avoid race with pageout ! 190: */ ! 191: if (type == CTEXT && fileno != PG_FZERO && !nohash) { ! 192: while ((c = mfind(getfsx(dev), bncache)) != 0) { ! 193: pf = cmtopg(c - cmap); ! 194: if (c->c_lock == 0) ! 195: break; ! 196: mlock(pf); ! 197: munlock(pf); ! 198: } ! 199: if (c) { ! 200: dbcmap = *c; ! 201: if (c->c_type != CTEXT || c->c_gone == 0 || ! 202: c->c_free == 0) ! 203: panic("pagein mfind"); ! 204: p->p_textp->x_rssize += CLSIZE; ! 205: /* ! 206: * Following code mimics memall(). ! 207: */ ! 208: pf = cmtopg(c - cmap); ! 209: munlink(pf); ! 210: for (j = 0; j < CLSIZE; j++) { ! 211: *(int *)pte = pf++; ! 212: pte->pg_prot = opte.pg_prot; ! 213: pte++; ! 214: } ! 215: pte -= CLSIZE; ! 216: c->c_free = 0; ! 217: c->c_gone = 0; ! 218: if (c->c_intrans || c->c_want) ! 219: panic("pagein intrans|want"); ! 220: c->c_lock = 1; ! 221: if (c->c_page != vtotp(p, v)) ! 222: panic("pagein c_page chgd"); ! 223: c->c_ndx = p->p_textp - &text[0]; ! 224: if (dev == swapdev) ! 225: cnt.v_xsfrec++; ! 226: else ! 227: cnt.v_xifrec++; ! 228: cnt.v_pgrec++; ! 229: uu->u_vm.vm_minflt++; ! 230: if (dev != swapdev) { ! 231: c = mfind(MSWAPX, bnswap); ! 232: if (c) ! 233: munhash(MSWAPX, bnswap); ! 234: pte->pg_swapm = 1; ! 235: } ! 236: goto skipswap; ! 237: } ! 238: } ! 239: ! 240: /* ! 241: * Wasn't reclaimable or reattachable. ! 242: * Have to prepare to bring the page in. ! 243: * We allocate the page before locking so we will ! 244: * be swappable if there is no free memory. ! 245: * If we block we have to start over, since anything ! 246: * could have happened. ! 247: */ ! 248: if (freemem < CLSIZE * KLMAX) { ! 249: while (freemem < CLSIZE * KLMAX) ! 250: sleep((caddr_t)&freemem, PSWP+2); ! 251: pte = vtopte(p, v); ! 252: if (pte->pg_v) ! 253: goto valid; ! 254: goto restart; ! 255: } ! 256: ! 257: /* ! 258: * Now can get memory and committed to bringing in the page. ! 259: * Lock this process, get a page, ! 260: * construct the new pte, and increment ! 261: * the (process or text) resident set size. ! 262: */ ! 263: p->p_flag |= SPAGE; ! 264: (void) memall(pte, CLSIZE, p, type); ! 265: pte->pg_prot = opte.pg_prot; ! 266: pf = pte->pg_pfnum; ! 267: cmap[pgtocm(pf)].c_intrans = 1; ! 268: distcl(pte); ! 269: if (type == CTEXT) { ! 270: p->p_textp->x_rssize += CLSIZE; ! 271: distpte(p->p_textp, vtotp(p, v), pte); ! 272: } else ! 273: p->p_rssize += CLSIZE; ! 274: ! 275: /* ! 276: * Two cases: either fill on demand (zero or text) ! 277: * or from swap space. ! 278: */ ! 279: if (opte.pg_fod) { ! 280: pte->pg_swapm = 1; ! 281: if (fileno == PG_FZERO || fileno == PG_FTEXT) { ! 282: /* ! 283: * Flush any previous text page use of this ! 284: * swap device block. ! 285: */ ! 286: if (type == CTEXT) { ! 287: c = mfind(MSWAPX, bnswap); ! 288: if (c) ! 289: munhash(MSWAPX, bnswap); ! 290: } ! 291: /* ! 292: * If zero fill, short-circuit hard work ! 293: * by just clearing pages. ! 294: */ ! 295: if (fileno == PG_FZERO) { ! 296: for (i = 0; i < CLSIZE; i++) ! 297: clearseg(pf+i); ! 298: if (type != CTEXT) ! 299: cnt.v_zfod += CLSIZE; ! 300: goto skipswap; ! 301: } ! 302: cnt.v_exfod += CLSIZE; ! 303: } else ! 304: /* ! 305: * Vreading block... whoops ! 306: */ ! 307: panic("pagein, vrpages ref'd"); ! 308: /* ! 309: * Check that block is not in file system buffer cache. ! 310: * The way the cache is handled now, this ! 311: * happens only once every 2 days. ! 312: */ ! 313: if (bp = baddr(dev, bn)) { ! 314: pte->pg_v = 1; ! 315: prot = *(int *)pte & PG_PROT; ! 316: pte->pg_prot = 0; ! 317: *(int *)pte |= PG_UW; ! 318: distcl(pte); ! 319: tbiscl(v); ! 320: /* THIS ASSUMES THAT CLSIZE*NBPG==BSIZE */ ! 321: bcopy(bp->b_un.b_addr, ptob(v), BSIZE(dev)); ! 322: brelse(bp); ! 323: pte->pg_prot = 0; ! 324: *(int *)pte |= prot; ! 325: goto skipswap; ! 326: } ! 327: } else { ! 328: if (opte.pg_pfnum) ! 329: panic("pagein pfnum"); ! 330: /* ! 331: * Fill from swap area. Try to find adjacent ! 332: * pages to bring in also. ! 333: */ ! 334: v = kluster(p, v, pte, B_READ, &klsize, ! 335: (type == CTEXT) ? kltxt : ! 336: ((p->p_flag & SSEQL) ? klseql : klin), bn); ! 337: /* THIS COULD BE COMPUTED INCREMENTALLY... */ ! 338: bncache = bn = dbtofsb(swapdev, vtod(p, v, &uu->u_dmap, &uu->u_smap)); ! 339: } ! 340: ! 341: distcl(pte); ! 342: swap(p, fsbtodb(dev, bn), ptob(v), klsize * ctob(CLSIZE), ! 343: B_READ, B_PGIN, dev, 0); ! 344: ! 345: /* ! 346: * Instrumentation. ! 347: */ ! 348: uu->u_vm.vm_majflt++; ! 349: cnt.v_pgin++; ! 350: cnt.v_pgpgin += klsize * CLSIZE; ! 351: a = vmtime(otime, olbolt, oicr) / 100; ! 352: pgintime += a; ! 353: if (a >= 0) ! 354: vmfltmon(pmon, a, pmonmin, pres, NPMON); ! 355: ! 356: skipswap: ! 357: /* ! 358: * Fix page table entries. ! 359: * ! 360: * Only page requested in is validated, and rest of pages ! 361: * can be ``reclaimed''. This allows system to reclaim prepaged pages ! 362: * quickly if they are not used and memory is tight. ! 363: */ ! 364: pte = vtopte(p, vsave); ! 365: pte->pg_v = 1; ! 366: distcl(pte); ! 367: if (type == CTEXT) { ! 368: distpte(p->p_textp, vtotp(p, vsave), pte); ! 369: if (opte.pg_fod) ! 370: p->p_textp->x_flag |= XWRIT; ! 371: wakeup((caddr_t)p->p_textp); ! 372: } ! 373: ! 374: /* ! 375: * Memall returned page(s) locked. Unlock all ! 376: * pages in cluster. If locking pages for raw i/o ! 377: * leave the page which was required to be paged in locked, ! 378: * but still unlock others. ! 379: * If text pages, hash into the cmap situation table. ! 380: */ ! 381: pte = vtopte(p, v); ! 382: for (i = 0; i < klsize; i++) { ! 383: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 384: c->c_intrans = 0; ! 385: if (type == CTEXT && c->c_blkno == 0 && bncache && !nohash) { ! 386: mhash(c, getfsx(dev), bncache); ! 387: bncache++; ! 388: } ! 389: if (v != vsave || (p->p_flag & SDLYU) == 0) ! 390: munlock(pte->pg_pfnum); ! 391: if (v != vsave && type != CTEXT && preptofree) { ! 392: /* ! 393: * Throw pre-paged data/stack pages at the ! 394: * bottom of the free list. ! 395: */ ! 396: p->p_rssize -= CLSIZE; ! 397: memfree(pte, CLSIZE, 0); ! 398: } ! 399: tbiscl(v); /* conservative ? */ ! 400: v += CLSIZE; ! 401: pte += CLSIZE; ! 402: } ! 403: ! 404: /* ! 405: * All done. ! 406: */ ! 407: p->p_flag &= ~SPAGE; ! 408: if (p->p_flag & SPROCWT) { ! 409: register s = spl6(); ! 410: p->p_flag &= ~SPROCWT; ! 411: p->p_usrpri = 127; ! 412: wakeup((caddr_t)&(p->p_stat)); ! 413: ++runrun; ! 414: splx(s); ! 415: } ! 416: ! 417: /* ! 418: * If process is declared fifo, memory is tight, ! 419: * and this was a data page-in, free memory ! 420: * klsdist pagein clusters away from the current fault. ! 421: */ ! 422: if ((p->p_flag&SSEQL) && freemem < lotsfree && ! 423: type == CDATA && p == u.u_procp) { ! 424: int k = (vtodp(p, vsave) / CLSIZE) / klseql; ! 425: #ifdef notdef ! 426: if (vsave > uu->u_vsave) ! 427: k -= klsdist; ! 428: else ! 429: k += klsdist; ! 430: dpageout(p, k * klseql * CLSIZE, klout*CLSIZE); ! 431: uu->u_vsave = vsave; ! 432: #else ! 433: dpageout(p, (k - klsdist) * klseql * CLSIZE, klout*CLSIZE); ! 434: dpageout(p, (k + klsdist) * klseql * CLSIZE, klout*CLSIZE); ! 435: #endif ! 436: } ! 437: } ! 438: ! 439: #if defined(BERT) ! 440: int dmod = 1000000; ! 441: int dcnt; ! 442: #endif ! 443: /* ! 444: * Take away n pages of data space ! 445: * starting at data page dp. ! 446: * Used to take pages away from sequential processes. ! 447: * Mimics pieces of code in pageout() below. ! 448: */ ! 449: dpageout(p, dp, n) ! 450: struct proc *p; ! 451: int dp, n; ! 452: { ! 453: register struct cmap *c; ! 454: int i, klsize; ! 455: register struct pte *pte; ! 456: unsigned v; ! 457: daddr_t daddr; ! 458: ! 459: if (dp < 0) { ! 460: n += dp; ! 461: dp = 0; ! 462: } ! 463: if (dp + n > p->p_dsize) ! 464: n = p->p_dsize - dp; ! 465: #if defined(BERT) ! 466: if (++dcnt % dmod == 0) ! 467: printf("dp %d, n %d\n", dp, n); ! 468: #endif ! 469: for (i = 0; i < n; i += CLSIZE, dp += CLSIZE) { ! 470: pte = dptopte(p, dp); ! 471: if (pte->pg_fod || pte->pg_pfnum == 0) ! 472: continue; ! 473: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 474: if (c->c_lock || c->c_free) ! 475: continue; ! 476: if (pte->pg_v) { ! 477: pte->pg_v = 0; ! 478: if (anycl(pte, pg_m)) ! 479: pte->pg_m = 1; ! 480: distcl(pte); ! 481: } ! 482: if (dirtycl(pte)) { ! 483: if (bswlist.av_forw == NULL) ! 484: continue; ! 485: mlock(pte->pg_pfnum); ! 486: if (anycl(pte, pg_m)) { ! 487: pte->pg_m = 0; ! 488: } ! 489: pte->pg_swapm = 0; ! 490: distcl(pte); ! 491: p->p_poip++; ! 492: v = kluster(p, dptov(p, dp), pte, B_WRITE, ! 493: &klsize, klout, (daddr_t)0); ! 494: /* THIS ASSUMES THAT p == u.u_procp */ ! 495: daddr = vtod(p, v, &u.u_dmap, &u.u_smap); ! 496: swap(p, daddr, ptob(v), klsize * ctob(CLSIZE), ! 497: B_WRITE, B_DIRTY, swapdev, pte->pg_pfnum); ! 498: } else { ! 499: if (c->c_gone == 0) ! 500: p->p_rssize -= CLSIZE; ! 501: memfree(pte, CLSIZE, 0); ! 502: cnt.v_seqfree += CLSIZE; ! 503: } ! 504: } ! 505: } ! 506: ! 507: int fifo = 0; ! 508: /* ! 509: * The page out daemon, which runs as process 2. ! 510: * ! 511: * As long as there are at least lotsfree pages, ! 512: * this process is not run. When the number of free ! 513: * pages stays in the range desfree to lotsfree, ! 514: * this daemon runs through the pages in the loop ! 515: * at a rate determined in vmsched(), simulating the missing ! 516: * hardware reference bit, and cleaning pages and transferring ! 517: * them to the free list. ! 518: */ ! 519: int hand; ! 520: pageout() ! 521: { ! 522: register struct proc *rp; ! 523: register struct text *xp; ! 524: register struct cmap *c; ! 525: register struct pte *pte; ! 526: int count, pushes; ! 527: swblk_t daddr; ! 528: unsigned v; ! 529: int maxhand = pgtocm(maxfree); ! 530: int klsize; ! 531: ! 532: loop: ! 533: /* ! 534: * Before sleeping, look to see if there are any swap I/O headers ! 535: * in the ``cleaned'' list that correspond to dirty ! 536: * pages that have been pushed asynchronously. If so, ! 537: * empty the list by calling cleanup(). ! 538: * ! 539: * N.B.: We guarantee never to block while the cleaned list is nonempty. ! 540: */ ! 541: (void) spl6(); ! 542: if (bclnlist != NULL) ! 543: cleanup(); ! 544: sleep((caddr_t)&proc[PAGEPID], PSWP+1); ! 545: (void) spl0(); ! 546: count = 0; ! 547: pushes = 0; ! 548: while (nscan < desscan && freemem < lotsfree) { ! 549: top: ! 550: /* ! 551: * An iteration of the clock pointer (hand) around the loop. ! 552: * Look at the page at hand. If it is a ! 553: * locked (for physical i/o e.g.), system (u., page table) ! 554: * or free, then leave it alone. ! 555: * Otherwise, find a process and text pointer for the ! 556: * page, and a virtual page number in either the ! 557: * process or the text image. ! 558: */ ! 559: c = &cmap[hand]; ! 560: if (c->c_lock || c->c_free) ! 561: goto skip; ! 562: switch (c->c_type) { ! 563: ! 564: case CSYS: ! 565: goto skip; ! 566: ! 567: case CTEXT: ! 568: xp = &text[c->c_ndx]; ! 569: rp = xp->x_caddr; ! 570: v = tptov(rp, c->c_page); ! 571: pte = tptopte(rp, c->c_page); ! 572: break; ! 573: ! 574: case CDATA: ! 575: case CSTACK: ! 576: rp = &proc[c->c_ndx]; ! 577: /* xp = rp->p_textp; */ ! 578: if (c->c_type == CDATA) { ! 579: v = dptov(rp, c->c_page); ! 580: pte = dptopte(rp, c->c_page); ! 581: } else { ! 582: v = sptov(rp, c->c_page); ! 583: pte = sptopte(rp, c->c_page); ! 584: } ! 585: break; ! 586: } ! 587: if (pte->pg_pfnum != cmtopg(hand)) ! 588: panic("bad c_page"); ! 589: /* ! 590: * If page is valid; make invalid but reclaimable. ! 591: * If this pte is not valid, then it must be reclaimable ! 592: * and we can add it to the free list. ! 593: */ ! 594: if (pte->pg_v) { ! 595: pte->pg_v = 0; ! 596: if (anycl(pte, pg_m)) ! 597: pte->pg_m = 1; ! 598: distcl(pte); ! 599: if (c->c_type == CTEXT) ! 600: distpte(xp, vtotp(rp, v), pte); ! 601: if ((rp->p_flag & (SSEQL|SUANOM)) || fifo || ! 602: rp->p_rssize > rp->p_maxrss) ! 603: goto take; ! 604: } else { ! 605: take: ! 606: if (c->c_type != CTEXT) { ! 607: /* ! 608: * Guarantee a minimal investment in data ! 609: * space for jobs in balance set. ! 610: */ ! 611: if (rp->p_rssize < saferss - rp->p_slptime) ! 612: goto skip; ! 613: } ! 614: ! 615: /* ! 616: * If the page is currently dirty, we ! 617: * have to arrange to have it cleaned before it ! 618: * can be freed. We mark it clean immediately. ! 619: * If it is reclaimed while being pushed, then modified ! 620: * again, we are assured of the correct order of ! 621: * writes because we lock the page during the write. ! 622: * This guarantees that a swap() of this process (and ! 623: * thus this page), initiated in parallel, will, ! 624: * in fact, push the page after us. ! 625: * ! 626: * The most general worst case here would be for ! 627: * a reclaim, a modify and a swapout to occur ! 628: * all before the single page transfer completes. ! 629: */ ! 630: if (dirtycl(pte)) { ! 631: /* ! 632: * Limit pushes to avoid saturating ! 633: * pageout device. ! 634: * ! 635: * MAGIC 4 BECAUSE WE RUN EVERY 1/4 SEC (clock) ! 636: */ ! 637: if (pushes > maxpgio / 4) ! 638: goto skip; ! 639: pushes++; ! 640: /* ! 641: * If the process is being swapped out ! 642: * or about to exit, do not bother with its ! 643: * dirty pages ! 644: */ ! 645: if (rp->p_flag & (SLOCK|SWEXIT)) ! 646: goto skip; ! 647: ! 648: /* ! 649: * Now carefully make sure that there will ! 650: * be a header available for the push so that ! 651: * we will not block waiting for a header in ! 652: * swap(). The reason this is important is ! 653: * that we (proc[PAGEPID]) are the one who cleans ! 654: * dirty swap headers and we could otherwise ! 655: * deadlock waiting for ourselves to clean ! 656: * swap headers. The sleep here on &proc[PAGEPID] ! 657: * is actually (effectively) a sleep on both ! 658: * ourselves and &bswlist, and this is known ! 659: * to iodone and swap in bio.c. That is, ! 660: * &proc[PAGEPID] will be awakened both when dirty ! 661: * headers show up and also to get the pageout ! 662: * daemon moving. ! 663: */ ! 664: (void) spl6(); ! 665: if (bclnlist != NULL) ! 666: cleanup(); ! 667: if (bswlist.av_forw == NULL) { ! 668: bswlist.b_flags |= B_WANTED; ! 669: sleep((caddr_t)&proc[PAGEPID], PSWP+2); ! 670: (void) spl0(); ! 671: /* ! 672: * Page disposition may have changed ! 673: * since process may have exec'ed, ! 674: * forked, exited or just about ! 675: * anything else... try this page ! 676: * frame again, from the top. ! 677: */ ! 678: goto top; ! 679: } ! 680: (void) spl0(); ! 681: ! 682: mlock((unsigned)cmtopg(hand)); ! 683: uaccess(rp, Pushmap, pushutl); ! 684: /* ! 685: * Now committed to pushing the page... ! 686: */ ! 687: if (anycl(pte, pg_m)) { ! 688: pte->pg_m = 0; ! 689: } ! 690: pte->pg_swapm = 0; ! 691: distcl(pte); ! 692: if (c->c_type == CTEXT) { ! 693: xp->x_poip++; ! 694: distpte(xp, vtotp(rp, v), pte); ! 695: } else ! 696: rp->p_poip++; ! 697: v = kluster(rp, v, pte, B_WRITE, &klsize, klout, (daddr_t)0); ! 698: if (klsize == 0) ! 699: panic("pageout klsize"); ! 700: daddr = vtod(rp, v, &pushutl->u_dmap, &pushutl->u_smap); ! 701: swap(rp, daddr, ptob(v), klsize * ctob(CLSIZE), ! 702: B_WRITE, B_DIRTY, swapdev, pte->pg_pfnum); ! 703: /* ! 704: * The cleaning of this page will be ! 705: * completed later, in cleanup() called ! 706: * (synchronously) by us (proc[PAGEPID]). In ! 707: * the meantime, the page frame is locked ! 708: * so no havoc can result. ! 709: */ ! 710: goto skip; ! 711: ! 712: } ! 713: /* ! 714: * Decrement the resident set size of the current ! 715: * text object/process, and put the page in the ! 716: * free list. Note that we don't give memfree the ! 717: * pte as its argument, since we don't want to destroy ! 718: * the pte. If it hasn't already been discarded ! 719: * it may yet have a chance to be reclaimed from ! 720: * the free list. ! 721: */ ! 722: if (c->c_gone == 0) ! 723: if (c->c_type == CTEXT) ! 724: xp->x_rssize -= CLSIZE; ! 725: else ! 726: rp->p_rssize -= CLSIZE; ! 727: memfree(pte, CLSIZE, 0); ! 728: cnt.v_dfree += CLSIZE; ! 729: ! 730: /* ! 731: * We managed to add a page to the free list, ! 732: * so we give ourselves another couple of trips ! 733: * around the loop. ! 734: */ ! 735: count = 0; ! 736: } ! 737: skip: ! 738: cnt.v_scan++; ! 739: nscan++; ! 740: if (++hand >= maxhand) { ! 741: hand = 0; ! 742: cnt.v_rev++; ! 743: if (count > 2) { ! 744: /* ! 745: * Extremely unlikely, but we went around ! 746: * the loop twice and didn't get anywhere. ! 747: * Don't cycle, stop till the next clock tick. ! 748: */ ! 749: goto loop; ! 750: } ! 751: count++; ! 752: } ! 753: } ! 754: goto loop; ! 755: } ! 756: ! 757: /* ! 758: * Process the ``cleaned'' list. ! 759: * ! 760: * Scan through the linked list of swap I/O headers ! 761: * and free the corresponding pages that have been ! 762: * cleaned by being written back to the paging area. ! 763: * If the page has been reclaimed during this time, ! 764: * we do not free the page. As they are processed, ! 765: * the swap I/O headers are removed from the cleaned ! 766: * list and inserted into the free list. ! 767: */ ! 768: cleanup() ! 769: { ! 770: register struct buf *bp; ! 771: register struct proc *rp; ! 772: register struct text *xp; ! 773: register struct cmap *c; ! 774: register struct pte *pte; ! 775: unsigned pf; ! 776: register int i; ! 777: int s; ! 778: ! 779: for (;;) { ! 780: s = spl6(); ! 781: if ((bp = bclnlist) == NULL) { ! 782: splx(s); ! 783: break; ! 784: } ! 785: bclnlist = bp->av_forw; ! 786: splx(s); ! 787: pte = dptopte(&proc[PAGEPID], btop(bp->b_un.b_addr)); ! 788: for (i = 0; i < bp->b_bcount; i += CLSIZE * NBPG) { ! 789: pf = pte->pg_pfnum; ! 790: munlock(pf); ! 791: c = &cmap[pgtocm(pf)]; ! 792: if (c->c_gone) { ! 793: memfree(pte, CLSIZE, 0); ! 794: cnt.v_dfree += CLSIZE; ! 795: } ! 796: pte += CLSIZE; ! 797: } ! 798: c = &cmap[pgtocm(bp->b_pfcent)]; ! 799: switch (c->c_type) { ! 800: ! 801: case CSYS: ! 802: panic("cleanup CSYS"); ! 803: ! 804: case CTEXT: ! 805: xp = &text[c->c_ndx]; ! 806: xp->x_poip--; ! 807: if (xp->x_poip == 0) ! 808: wakeup((caddr_t)&xp->x_poip); ! 809: break; ! 810: ! 811: case CDATA: ! 812: case CSTACK: ! 813: rp = &proc[c->c_ndx]; ! 814: rp->p_poip--; ! 815: if (rp->p_poip == 0) ! 816: wakeup((caddr_t)&rp->p_poip); ! 817: break; ! 818: } ! 819: if (c->c_gone == 0) { ! 820: switch (c->c_type) { ! 821: ! 822: case CTEXT: ! 823: pte = tptopte(xp->x_caddr, c->c_page); ! 824: break; ! 825: ! 826: case CDATA: ! 827: pte = dptopte(rp, c->c_page); ! 828: break; ! 829: ! 830: case CSTACK: ! 831: pte = sptopte(rp, c->c_page); ! 832: break; ! 833: } ! 834: if (pte->pg_v == 0) { ! 835: if (c->c_type == CTEXT) ! 836: xp->x_rssize -= CLSIZE; ! 837: else ! 838: rp->p_rssize -= CLSIZE; ! 839: memfree(pte, CLSIZE, 0); ! 840: cnt.v_dfree += CLSIZE; ! 841: } ! 842: } ! 843: bp->b_flags = 0; ! 844: bp->av_forw = bswlist.av_forw; ! 845: bswlist.av_forw = bp; ! 846: if (bswlist.b_flags & B_WANTED) { ! 847: bswlist.b_flags &= ~B_WANTED; ! 848: wakeup((caddr_t)&bswlist); ! 849: } ! 850: } ! 851: } ! 852: ! 853: /* ! 854: * Kluster locates pages adjacent to the argument pages ! 855: * that are immediately available to include in the pagein/pageout, ! 856: * and given the availability of memory includes them. ! 857: * It knows that the process image is contiguous in chunks; ! 858: * an assumption here is that CLSIZE * KLMAX is a divisor of dmmin, ! 859: * so that by looking at KLMAX chunks of pages, all such will ! 860: * necessarily be mapped swap contiguous. ! 861: */ ! 862: int noklust; ! 863: int klicnt[KLMAX]; ! 864: int klocnt[KLMAX]; ! 865: ! 866: kluster(p, v, pte0, rw, pkl, klsize, bn0) ! 867: register struct proc *p; ! 868: unsigned v; ! 869: struct pte *pte0; ! 870: int rw, *pkl, klsize; ! 871: daddr_t bn0; ! 872: { ! 873: int type, cl, clmax; ! 874: int kloff, k, klmax; ! 875: register struct pte *pte; ! 876: int klback, klforw; ! 877: register int i; ! 878: unsigned v0; ! 879: daddr_t bn; ! 880: ! 881: if (rw == B_READ) ! 882: klicnt[0]++; ! 883: else ! 884: klocnt[0]++; ! 885: *pkl = 1; ! 886: if (noklust || klsize <= 1 || klsize > KLMAX || (klsize & (klsize - 1))) ! 887: return (v); ! 888: if (rw == B_READ && freemem < CLSIZE * KLMAX) ! 889: return (v); ! 890: if (isassv(p, v)) { ! 891: type = CSTACK; ! 892: cl = vtosp(p, v) / CLSIZE; ! 893: clmax = p->p_ssize / CLSIZE; ! 894: } else if (isadsv(p, v)) { ! 895: type = CDATA; ! 896: cl = vtodp(p, v) / CLSIZE; ! 897: clmax = p->p_dsize / CLSIZE; ! 898: } else { ! 899: type = CTEXT; ! 900: cl = vtotp(p, v) / CLSIZE; ! 901: clmax = p->p_textp->x_size / CLSIZE; ! 902: } ! 903: kloff = cl & (klsize - 1); ! 904: pte = pte0; ! 905: bn = bn0; ! 906: for (k = kloff; --k >= 0;) { ! 907: if (type == CSTACK) ! 908: pte += CLSIZE; ! 909: else ! 910: pte -= CLSIZE; ! 911: if (type == CTEXT && rw == B_READ && bn) { ! 912: bn--; ! 913: if (mfind(MSWAPX, bn)) ! 914: break; ! 915: } ! 916: if (!klok(pte, rw)) ! 917: break; ! 918: } ! 919: klback = (kloff - k) - 1; ! 920: pte = pte0; ! 921: if ((cl - kloff) + klsize > clmax) ! 922: klmax = clmax - (cl - kloff); ! 923: else ! 924: klmax = klsize; ! 925: bn = bn0; ! 926: for (k = kloff; ++k < klmax;) { ! 927: if (type == CSTACK) ! 928: pte -= CLSIZE; ! 929: else ! 930: pte += CLSIZE; ! 931: if (type == CTEXT && rw == B_READ && bn) { ! 932: bn++; ! 933: if (mfind(MSWAPX, bn)) ! 934: break; ! 935: } ! 936: if (!klok(pte, rw)) ! 937: break; ! 938: } ! 939: klforw = (k - kloff) - 1; ! 940: if (klforw + klback == 0) ! 941: return (v); ! 942: pte = pte0; ! 943: if (type == CSTACK) { ! 944: pte -= klforw * CLSIZE; ! 945: v -= klforw * CLSIZE; ! 946: } else { ! 947: pte -= klback * CLSIZE; ! 948: v -= klback * CLSIZE; ! 949: } ! 950: *pkl = klforw + klback + 1; ! 951: if (rw == B_READ) ! 952: klicnt[0]--, klicnt[*pkl - 1]++; ! 953: else ! 954: klocnt[0]--, klocnt[*pkl - 1]++; ! 955: v0 = v; ! 956: for (i = 0; i < *pkl; i++) { ! 957: if (pte == pte0) ! 958: goto cont; ! 959: if (rw == B_WRITE) { ! 960: mlock(pte->pg_pfnum); ! 961: if (anycl(pte, pg_m)) { ! 962: pte->pg_m = 0; ! 963: } ! 964: pte->pg_swapm = 0; ! 965: distcl(pte); ! 966: if (type == CTEXT) ! 967: distpte(p->p_textp, vtotp(p, v), pte); ! 968: } else { ! 969: struct pte opte; ! 970: int pf; ! 971: ! 972: opte = *pte; ! 973: if (memall(pte, CLSIZE, p, type) == 0) ! 974: panic("kluster"); ! 975: pte->pg_prot = opte.pg_prot; ! 976: pf = pte->pg_pfnum; ! 977: cmap[pgtocm(pf)].c_intrans = 1; ! 978: distcl(pte); ! 979: if (type == CTEXT) { ! 980: p->p_textp->x_rssize += CLSIZE; ! 981: distpte(p->p_textp, vtotp(p, v), pte); ! 982: } else ! 983: p->p_rssize += CLSIZE; ! 984: distcl(pte); ! 985: } ! 986: cont: ! 987: pte += CLSIZE; ! 988: v += CLSIZE; ! 989: } ! 990: return (v0); ! 991: } ! 992: ! 993: klok(pte, rw) ! 994: register struct pte *pte; ! 995: int rw; ! 996: { ! 997: register struct cmap *c; ! 998: ! 999: if (rw == B_WRITE) { ! 1000: if (pte->pg_fod) ! 1001: return (0); ! 1002: if (pte->pg_pfnum == 0) ! 1003: return (0); ! 1004: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 1005: if (c->c_lock || c->c_intrans) ! 1006: return (0); ! 1007: if (!dirtycl(pte)) ! 1008: return (0); ! 1009: return (1); ! 1010: } else { ! 1011: if (pte->pg_fod) ! 1012: return (0); ! 1013: if (pte->pg_pfnum) ! 1014: return (0); ! 1015: return (1); ! 1016: } ! 1017: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.