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