|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)vm_page.c 7.14 (Berkeley) 6/28/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "user.h" ! 26: #include "proc.h" ! 27: #include "buf.h" ! 28: #include "text.h" ! 29: #include "vnode.h" ! 30: #include "cmap.h" ! 31: #include "vm.h" ! 32: #include "trace.h" ! 33: #include "file.h" ! 34: ! 35: #include "machine/cpu.h" ! 36: #include "machine/pte.h" ! 37: #include "machine/mtpr.h" ! 38: ! 39: #if defined(tahoe) ! 40: #if CLSIZE == 1 ! 41: #define uncachecl(pte) uncache(pte) ! 42: #endif ! 43: #if CLSIZE == 2 ! 44: #define uncachecl(pte) uncache(pte), uncache((pte)+1) ! 45: #endif ! 46: #if CLSIZE > 2 ! 47: #define uncachecl(pte) { \ ! 48: register ii; \ ! 49: for (ii = 0; ii < CLSIZE; ii++) \ ! 50: uncache((pte) + ii); \ ! 51: } ! 52: #endif ! 53: #else /* tahoe */ ! 54: #define uncache(pte) /* nothing */ ! 55: #define uncachecl(pte) /* nothing */ ! 56: #endif ! 57: ! 58: int nohash = 0; ! 59: /* ! 60: * Handle a page fault. ! 61: * ! 62: * Basic outline ! 63: * If page is allocated, but just not valid: ! 64: * Wait if intransit, else just revalidate ! 65: * Done ! 66: * Compute <vp,bn> from which page operation would take place ! 67: * If page is text page, and filling from file system or swap space: ! 68: * If in free list cache, reattach it and then done ! 69: * Allocate memory for page in ! 70: * If block here, restart because we could have swapped, etc. ! 71: * Lock process from swapping for duration ! 72: * Update pte's to reflect that page is intransit. ! 73: * If page is zero fill on demand: ! 74: * Clear pages and flush free list cache of stale cacheing ! 75: * for this swap page (e.g. before initializing again due ! 76: * to 407/410 exec). ! 77: * If page is fill from file and in buffer cache: ! 78: * Copy the page from the buffer cache. ! 79: * If not a fill on demand: ! 80: * Determine swap address and cluster to page in ! 81: * Do the swap to bring the page in ! 82: * Instrument the pagein ! 83: * After swap validate the required new page ! 84: * Leave prepaged pages reclaimable (not valid) ! 85: * Update shared copies of text page tables ! 86: * Complete bookkeeping on pages brought in: ! 87: * No longer intransit ! 88: * Hash text pages into core hash structure ! 89: * Unlock pages (modulo raw i/o requirements) ! 90: * Flush translation buffer ! 91: * Process pagein is done ! 92: */ ! 93: #ifdef TRACE ! 94: #define pgtrace(e) trace(e,v,u.u_procp->p_pid) ! 95: #else ! 96: #define pgtrace(e) ! 97: #endif ! 98: ! 99: int preptofree = 1; /* send pre-paged pages to free list */ ! 100: ! 101: pagein(virtaddr, dlyu) ! 102: unsigned virtaddr; ! 103: int dlyu; ! 104: { ! 105: register struct proc *p; ! 106: register struct pte *pte; ! 107: register unsigned v; ! 108: unsigned pf; ! 109: int type, fileno; ! 110: struct pte opte; ! 111: struct vnode *vp; ! 112: register int i; ! 113: int klsize; ! 114: unsigned vsave; ! 115: struct cmap *c; ! 116: int j; ! 117: daddr_t bn, bncache, bnswap; ! 118: int si, sk; ! 119: int swerror = 0; ! 120: #ifdef PGINPROF ! 121: int otime, olbolt, oicr, s; ! 122: long a; ! 123: ! 124: s = splclock(); ! 125: otime = time, olbolt = lbolt, oicr = mfpr(ICR); ! 126: #endif ! 127: cnt.v_faults++; ! 128: /* ! 129: * Classify faulted page into a segment and get a pte ! 130: * for the faulted page. ! 131: */ ! 132: vsave = v = clbase(btop(virtaddr)); ! 133: p = u.u_procp; ! 134: if (isatsv(p, v)) ! 135: type = CTEXT; ! 136: else if (isassv(p, v)) ! 137: type = CSTACK; ! 138: else ! 139: type = CDATA; ! 140: pte = vtopte(p, v); ! 141: if (pte->pg_v) { ! 142: #ifdef MAPMEM ! 143: /* will this ever happen? */ ! 144: if (pte->pg_fod) { ! 145: #ifdef PGINPROF ! 146: splx(s); ! 147: #endif ! 148: return; ! 149: } ! 150: #endif ! 151: panic("pagein"); ! 152: } ! 153: ! 154: /* ! 155: * If page is reclaimable, reclaim it. ! 156: * If page is text and intransit, sleep while it is intransit, ! 157: * If it is valid after the sleep, we are done. ! 158: * Otherwise we have to start checking again, since page could ! 159: * even be reclaimable now (we may have swapped for a long time). ! 160: */ ! 161: restart: ! 162: if (pte->pg_fod == 0 && pte->pg_pfnum) { ! 163: if (type == CTEXT && cmap[pgtocm(pte->pg_pfnum)].c_intrans) { ! 164: pgtrace(TR_INTRANS); ! 165: sleep((caddr_t)p->p_textp, PSWP+1); ! 166: pgtrace(TR_EINTRANS); ! 167: pte = vtopte(p, v); ! 168: if (pte->pg_v) { ! 169: valid: ! 170: if (dlyu) { ! 171: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 172: if (c->c_lock) { ! 173: c->c_want = 1; ! 174: sleep((caddr_t)c, PSWP+1); ! 175: goto restart; ! 176: } ! 177: c->c_lock = 1; ! 178: } ! 179: newptes(pte, v, CLSIZE); ! 180: cnt.v_intrans++; ! 181: #ifdef PGINPROF ! 182: splx(s); ! 183: #endif ! 184: return; ! 185: } ! 186: goto restart; ! 187: } ! 188: /* ! 189: * If page is in the free list, then take ! 190: * it back into the resident set, updating ! 191: * the size recorded for the resident set. ! 192: */ ! 193: si = splimp(); ! 194: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 195: if (c->c_free) { ! 196: pgtrace(TR_FRECLAIM); ! 197: munlink(c); ! 198: cnt.v_pgfrec++; ! 199: if (type == CTEXT) ! 200: p->p_textp->x_rssize += CLSIZE; ! 201: else ! 202: p->p_rssize += CLSIZE; ! 203: } else ! 204: pgtrace(TR_RECLAIM); ! 205: splx(si); ! 206: uncachecl(pte); ! 207: pte->pg_v = 1; ! 208: if (anycl(pte, pg_m)) ! 209: pte->pg_m = 1; ! 210: distcl(pte); ! 211: if (type == CTEXT) ! 212: distpte(p->p_textp, (unsigned)vtotp(p, v), pte); ! 213: u.u_ru.ru_minflt++; ! 214: cnt.v_pgrec++; ! 215: if (dlyu) { ! 216: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 217: if (c->c_lock) { ! 218: c->c_want = 1; ! 219: sleep((caddr_t)c, PSWP+1); ! 220: goto restart; ! 221: } ! 222: c->c_lock = 1; ! 223: } ! 224: newptes(pte, v, CLSIZE); ! 225: #ifdef PGINPROF ! 226: a = vmtime(otime, olbolt, oicr); ! 227: rectime += a; ! 228: if (a >= 0) ! 229: vmfltmon(rmon, a, rmonmin, rres, NRMON); ! 230: splx(s); ! 231: #endif ! 232: return; ! 233: } ! 234: #ifdef PGINPROF ! 235: splx(s); ! 236: #endif ! 237: /* ! 238: * <vp,bn> is where data comes from/goes to. ! 239: * <vp,bncache> is where data is cached from/to. ! 240: * <swapdev_vp,bnswap> is where data will eventually go. ! 241: */ ! 242: if (pte->pg_fod == 0) { ! 243: fileno = -1; ! 244: bnswap = bncache = bn = vtod(p, v, &u.u_dmap, &u.u_smap); ! 245: vp = swapdev_vp; ! 246: } else { ! 247: fileno = ((struct fpte *)pte)->pg_fileno; ! 248: bn = ((struct fpte *)pte)->pg_blkno; ! 249: bnswap = vtod(p, v, &u.u_dmap, &u.u_smap); ! 250: if (fileno == PG_FTEXT) { ! 251: if (p->p_textp == 0) ! 252: panic("pagein PG_FTEXT"); ! 253: if (VOP_BMAP(p->p_textp->x_vptr, (daddr_t)0, &vp, ! 254: (daddr_t *)0)) { ! 255: swkill(p, "pagein: filesystem unmounted"); ! 256: return; ! 257: } ! 258: bncache = bn; ! 259: } else if (fileno == PG_FZERO) { ! 260: vp = swapdev_vp; ! 261: bncache = bnswap; ! 262: } ! 263: } ! 264: klsize = 1; ! 265: opte = *pte; ! 266: ! 267: /* ! 268: * Check for text detached but in free list. ! 269: * This can happen only if the page is filling ! 270: * from a inode or from the swap device, (e.g. not when reading ! 271: * in 407/410 execs to a zero fill page.) ! 272: * Honor lock bit to avoid races with pageouts. ! 273: */ ! 274: if (type == CTEXT && fileno != PG_FZERO && !nohash) { ! 275: si = splimp(); ! 276: while ((c = mfind(vp, bncache)) != 0) { ! 277: if (c->c_lock == 0) ! 278: break; ! 279: MLOCK(c); ! 280: MUNLOCK(c); ! 281: } ! 282: if (c) { ! 283: if (c->c_type != CTEXT || c->c_gone == 0 || ! 284: c->c_free == 0) ! 285: panic("pagein mfind"); ! 286: p->p_textp->x_rssize += CLSIZE; ! 287: /* ! 288: * Following code mimics memall(). ! 289: */ ! 290: munlink(c); ! 291: pf = cmtopg(c - cmap); ! 292: for (j = 0; j < CLSIZE; j++) { ! 293: *(int *)pte = 0; ! 294: pte->pg_pfnum = pf++; ! 295: pte->pg_prot = opte.pg_prot; ! 296: pte++; ! 297: } ! 298: pte -= CLSIZE; ! 299: c->c_free = 0; ! 300: c->c_gone = 0; ! 301: if (c->c_intrans || c->c_want) ! 302: panic("pagein intrans|want"); ! 303: c->c_lock = 1; ! 304: if (c->c_page != vtotp(p, v)) ! 305: panic("pagein c_page chgd"); ! 306: c->c_ndx = p->p_textp - &text[0]; ! 307: if (vp == swapdev_vp) { ! 308: cnt.v_xsfrec++; ! 309: pgtrace(TR_XSFREC); ! 310: } else { ! 311: cnt.v_xifrec++; ! 312: pgtrace(TR_XIFREC); ! 313: } ! 314: cnt.v_pgrec++; ! 315: u.u_ru.ru_minflt++; ! 316: if (vp != swapdev_vp) { ! 317: munhash(swapdev_vp, bnswap); ! 318: pte->pg_m = 1; ! 319: } ! 320: splx(si); ! 321: goto skipswap; ! 322: } ! 323: splx(si); ! 324: } ! 325: ! 326: /* ! 327: * Wasn't reclaimable or reattachable. ! 328: * Have to prepare to bring the page in. ! 329: * We allocate the page before locking so we will ! 330: * be swappable if there is no free memory. ! 331: * If we block we have to start over, since anything ! 332: * could have happened. ! 333: */ ! 334: sk = splimp(); /* lock memalls from here into kluster */ ! 335: if (freemem < CLSIZE * KLMAX) { ! 336: pgtrace(TR_WAITMEM); ! 337: while (freemem < CLSIZE * KLMAX) ! 338: sleep((caddr_t)&freemem, PSWP+2); ! 339: pgtrace(TR_EWAITMEM); ! 340: splx(sk); ! 341: pte = vtopte(p, v); ! 342: #ifdef PGINPROF ! 343: s = splclock(); ! 344: #endif ! 345: if (pte->pg_v) ! 346: goto valid; ! 347: goto restart; ! 348: } ! 349: ! 350: /* ! 351: * Now can get memory and committed to bringing in the page. ! 352: * Lock this process, get a page, ! 353: * construct the new pte, and increment ! 354: * the (process or text) resident set size. ! 355: */ ! 356: p->p_flag |= SPAGE; ! 357: if (memall(pte, CLSIZE, p, type) == 0) ! 358: panic("pagein memall"); ! 359: pte->pg_prot = opte.pg_prot; ! 360: pf = pte->pg_pfnum; ! 361: cmap[pgtocm(pf)].c_intrans = 1; ! 362: distcl(pte); ! 363: if (type == CTEXT) { ! 364: p->p_textp->x_rssize += CLSIZE; ! 365: distpte(p->p_textp, (unsigned)vtotp(p, v), pte); ! 366: } else ! 367: p->p_rssize += CLSIZE; ! 368: ! 369: /* ! 370: * Two cases: either fill on demand (zero, or from file or text) ! 371: * or from swap space. ! 372: */ ! 373: if (opte.pg_fod) { ! 374: pte->pg_m = 1; ! 375: if (fileno == PG_FZERO || fileno == PG_FTEXT) { ! 376: /* ! 377: * Flush any previous text page use of this ! 378: * swap device block. ! 379: */ ! 380: if (type == CTEXT) ! 381: munhash(swapdev_vp, bnswap); ! 382: /* ! 383: * If zero fill, short-circuit hard work ! 384: * by just clearing pages. ! 385: */ ! 386: if (fileno == PG_FZERO) { ! 387: pgtrace(TR_ZFOD); ! 388: for (i = 0; i < CLSIZE; i++) { ! 389: clearseg(pf+i); ! 390: #if defined(tahoe) ! 391: mtpr(P1DC, (int)virtaddr + i * NBPG); ! 392: #endif ! 393: } ! 394: if (type != CTEXT) ! 395: cnt.v_zfod += CLSIZE; ! 396: splx(sk); ! 397: goto skipswap; ! 398: } ! 399: pgtrace(TR_EXFOD); ! 400: cnt.v_exfod += CLSIZE; ! 401: } ! 402: /* ! 403: * Fill from inode. Try to find adjacent ! 404: * pages to bring in also. ! 405: */ ! 406: v = fodkluster(p, v, pte, &klsize, vp, &bn); ! 407: bncache = bn; ! 408: splx(sk); ! 409: #ifdef TRACE ! 410: if (type != CTEXT) ! 411: trace(TR_XFODMISS, vp, bn); ! 412: #endif ! 413: } else { ! 414: if (opte.pg_pfnum) ! 415: panic("pagein pfnum"); ! 416: pgtrace(TR_SWAPIN); ! 417: /* ! 418: * Fill from swap area. Try to find adjacent ! 419: * pages to bring in also. ! 420: */ ! 421: v = kluster(p, v, pte, B_READ, &klsize, ! 422: (type == CTEXT) ? kltxt : ! 423: ((p->p_flag & SSEQL) ? klseql : klin), bn); ! 424: splx(sk); ! 425: /* THIS COULD BE COMPUTED INCREMENTALLY... */ ! 426: bncache = bn = vtod(p, v, &u.u_dmap, &u.u_smap); ! 427: } ! 428: ! 429: distcl(pte); ! 430: swerror = swap(p, bn, ptob(v), klsize * ctob(CLSIZE), ! 431: B_READ, B_PGIN, vp, 0); ! 432: #ifdef TRACE ! 433: trace(TR_PGINDONE, vsave, u.u_procp->p_pid); ! 434: #endif ! 435: ! 436: /* ! 437: * Instrumentation. ! 438: */ ! 439: u.u_ru.ru_majflt++; ! 440: cnt.v_pgin++; ! 441: cnt.v_pgpgin += klsize * CLSIZE; ! 442: #ifdef PGINPROF ! 443: a = vmtime(otime, olbolt, oicr) / 100; ! 444: pgintime += a; ! 445: if (a >= 0) ! 446: vmfltmon(pmon, a, pmonmin, pres, NPMON); ! 447: #endif ! 448: ! 449: skipswap: ! 450: /* ! 451: * Fix page table entries. ! 452: * ! 453: * Only page requested in is validated, and rest of pages ! 454: * can be ``reclaimed''. This allows system to reclaim prepaged pages ! 455: * quickly if they are not used and memory is tight. ! 456: */ ! 457: pte = vtopte(p, vsave); ! 458: pte->pg_v = 1; ! 459: #ifdef REFBIT ! 460: /* ! 461: * Start with the page used so that pageout doesn't free it ! 462: * immediately. ! 463: */ ! 464: pte->pg_u = 1; ! 465: #endif ! 466: distcl(pte); ! 467: if (type == CTEXT) { ! 468: if (swerror) { ! 469: xinval(p->p_textp->x_vptr); ! 470: } else { ! 471: distpte(p->p_textp, (unsigned)vtotp(p, vsave), pte); ! 472: if (opte.pg_fod) ! 473: p->p_textp->x_flag |= XWRIT; ! 474: } ! 475: wakeup((caddr_t)p->p_textp); ! 476: } ! 477: ! 478: /* ! 479: * Memall returned page(s) locked. Unlock all ! 480: * pages in cluster. If locking pages for raw i/o ! 481: * leave the page which was required to be paged in locked, ! 482: * but still unlock others. ! 483: * If text pages, hash into the cmap situation table. ! 484: */ ! 485: pte = vtopte(p, v); ! 486: for (i = 0; i < klsize; i++) { ! 487: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 488: c->c_intrans = 0; ! 489: if (type == CTEXT && c->c_blkno == 0 && bncache && !nohash && ! 490: !swerror) { ! 491: mhash(c, vp, bncache); ! 492: bncache += btodb(CLBYTES); ! 493: } ! 494: if (v != vsave || !dlyu) ! 495: MUNLOCK(c); ! 496: if (v != vsave && type != CTEXT && preptofree && ! 497: opte.pg_fod == 0) { ! 498: /* ! 499: * Throw pre-paged data/stack pages at the ! 500: * bottom of the free list; leave pg_u clear. ! 501: */ ! 502: p->p_rssize -= CLSIZE; ! 503: memfree(pte, CLSIZE, 0); ! 504: } ! 505: #ifdef REFBIT ! 506: /* ! 507: * Text pages paged-in and allocated during the kluster ! 508: * must be validated, as they are now in the resident set. ! 509: */ ! 510: if (v != vsave && type == CTEXT) { ! 511: pte->pg_v = 1; ! 512: distpte(p->p_textp, (unsigned)vtotp(p, v), pte); ! 513: } ! 514: #endif ! 515: newptes(pte, v, CLSIZE); ! 516: v += CLSIZE; ! 517: pte += CLSIZE; ! 518: } ! 519: ! 520: /* ! 521: * All done. ! 522: */ ! 523: p->p_flag &= ~SPAGE; ! 524: ! 525: /* ! 526: * If process is declared fifo, memory is tight, ! 527: * and this was a data page-in, free memory ! 528: * klsdist pagein clusters away from the current fault. ! 529: */ ! 530: if ((p->p_flag&SSEQL) && freemem < lotsfree && type == CDATA) { ! 531: int k = (vtodp(p, vsave) / CLSIZE) / klseql; ! 532: #ifdef notdef ! 533: if (vsave > u.u_vsave) ! 534: k -= klsdist; ! 535: else ! 536: k += klsdist; ! 537: dpageout(p, k * klseql * CLSIZE, klout*CLSIZE); ! 538: u.u_vsave = vsave; ! 539: #else ! 540: dpageout(p, (k - klsdist) * klseql * CLSIZE, klout*CLSIZE); ! 541: dpageout(p, (k + klsdist) * klseql * CLSIZE, klout*CLSIZE); ! 542: #endif ! 543: } ! 544: } ! 545: ! 546: /* ! 547: * Take away n pages of data space ! 548: * starting at data page dp. ! 549: * Used to take pages away from sequential processes. ! 550: * Mimics pieces of code in pageout() below. ! 551: */ ! 552: dpageout(p, dp, n) ! 553: struct proc *p; ! 554: int dp, n; ! 555: { ! 556: register struct cmap *c; ! 557: int i, klsize; ! 558: register struct pte *pte; ! 559: unsigned v; ! 560: daddr_t daddr; ! 561: ! 562: if (dp < 0) { ! 563: n += dp; ! 564: dp = 0; ! 565: } ! 566: if (dp + n > p->p_dsize) ! 567: n = p->p_dsize - dp; ! 568: for (i = 0; i < n; i += CLSIZE, dp += CLSIZE) { ! 569: pte = dptopte(p, dp); ! 570: if (pte->pg_fod || pte->pg_pfnum == 0) ! 571: continue; ! 572: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 573: if (c->c_lock || c->c_free) ! 574: continue; ! 575: uncachecl(pte); ! 576: if (pte->pg_v) { ! 577: pte->pg_v = 0; ! 578: if (anycl(pte, pg_m)) ! 579: pte->pg_m = 1; ! 580: distcl(pte); ! 581: p->p_flag |= SPTECHG; ! 582: } ! 583: if (dirtycl(pte)) { ! 584: if (bswlist.av_forw == NULL) ! 585: continue; ! 586: MLOCK(c); ! 587: pte->pg_m = 0; ! 588: distcl(pte); ! 589: p->p_poip++; ! 590: v = kluster(p, dptov(p, dp), pte, B_WRITE, ! 591: &klsize, klout, (daddr_t)0); ! 592: /* THIS ASSUMES THAT p == u.u_procp */ ! 593: daddr = vtod(p, v, &u.u_dmap, &u.u_smap); ! 594: (void) swap(p, daddr, ptob(v), klsize * ctob(CLSIZE), ! 595: B_WRITE, B_DIRTY, swapdev_vp, pte->pg_pfnum); ! 596: } else { ! 597: if (c->c_gone == 0) ! 598: p->p_rssize -= CLSIZE; ! 599: memfree(pte, CLSIZE, 0); ! 600: cnt.v_seqfree += CLSIZE; ! 601: } ! 602: } ! 603: } ! 604: ! 605: unsigned maxdmap; ! 606: unsigned maxtsize; ! 607: ! 608: /* ! 609: * Setup the paging constants for the clock algorithm. ! 610: * Called after the system is initialized and the amount of memory ! 611: * and number of paging devices is known. ! 612: * ! 613: * Threshold constants are defined in machine/vmparam.h. ! 614: */ ! 615: vminit() ! 616: { ! 617: ! 618: /* ! 619: * Lotsfree is threshold where paging daemon turns on. ! 620: */ ! 621: if (lotsfree == 0) { ! 622: lotsfree = LOTSFREE / NBPG; ! 623: if (lotsfree > LOOPPAGES / LOTSFREEFRACT) ! 624: lotsfree = LOOPPAGES / LOTSFREEFRACT; ! 625: } ! 626: /* ! 627: * Desfree is amount of memory desired free. ! 628: * If less than this for extended period, do swapping. ! 629: */ ! 630: if (desfree == 0) { ! 631: desfree = DESFREE / NBPG; ! 632: if (desfree > LOOPPAGES / DESFREEFRACT) ! 633: desfree = LOOPPAGES / DESFREEFRACT; ! 634: } ! 635: ! 636: /* ! 637: * Minfree is minimal amount of free memory which is tolerable. ! 638: */ ! 639: if (minfree == 0) { ! 640: minfree = MINFREE / NBPG; ! 641: if (minfree > desfree / MINFREEFRACT) ! 642: minfree = desfree / MINFREEFRACT; ! 643: } ! 644: ! 645: /* ! 646: * Maxpgio thresholds how much paging is acceptable. ! 647: * This figures that 2/3 busy on an arm is all that is ! 648: * tolerable for paging. We assume one operation per disk rev. ! 649: */ ! 650: if (maxpgio == 0) ! 651: maxpgio = (DISKRPM * 2) / 3; ! 652: ! 653: /* ! 654: * Clock to scan using max of ~~10% of processor time for sampling, ! 655: * this estimated to allow maximum of 200 samples per second. ! 656: * This yields a ``fastscan'' of roughly (with CLSIZE=2): ! 657: * <=1m 2m 3m 4m 8m ! 658: * 5s 10s 15s 20s 40s ! 659: */ ! 660: if (fastscan == 0) ! 661: fastscan = 200; ! 662: if (fastscan > LOOPPAGES / 5) ! 663: fastscan = LOOPPAGES / 5; ! 664: ! 665: /* ! 666: * Set slow scan time to 1/2 the fast scan time. ! 667: */ ! 668: if (slowscan == 0) ! 669: slowscan = fastscan / 2; ! 670: ! 671: /* ! 672: * Calculate the swap allocation constants. ! 673: */ ! 674: if (dmmin == 0) { ! 675: dmmin = DMMIN; ! 676: if (dmmin < CLBYTES/DEV_BSIZE) ! 677: dmmin = CLBYTES/DEV_BSIZE; ! 678: } ! 679: if (dmmax == 0) { ! 680: dmmax = DMMAX; ! 681: while (dmapsize(dmmin, dmmax / 2) >= MAXDSIZ && dmmax > dmmin) ! 682: dmmax /= 2; ! 683: } ! 684: maxdmap = dmapsize(dmmin, dmmax); ! 685: if (dmtext == 0) ! 686: dmtext = DMTEXT; ! 687: if (dmtext > dmmax) ! 688: dmtext = dmmax; ! 689: if (maxtsize == 0) ! 690: maxtsize = MAXTSIZ; ! 691: if (maxtsize > dtob(NXDAD * dmtext)) ! 692: maxtsize = dtob(NXDAD * dmtext); ! 693: ! 694: /* ! 695: * Set up the initial limits on process VM. ! 696: * Set the maximum resident set size to be all ! 697: * of (reasonably) available memory. This causes ! 698: * any single, large process to start random page ! 699: * replacement once it fills memory. ! 700: */ ! 701: u.u_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ; ! 702: u.u_rlimit[RLIMIT_STACK].rlim_max = MIN(MAXSSIZ, maxdmap); ! 703: u.u_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ; ! 704: u.u_rlimit[RLIMIT_DATA].rlim_max = MIN(MAXDSIZ, maxdmap); ! 705: u.u_rlimit[RLIMIT_RSS].rlim_cur = u.u_rlimit[RLIMIT_RSS].rlim_max = ! 706: ctob(LOOPPAGES - desfree); ! 707: proc[0].p_maxrss = LOOPPAGES - desfree; ! 708: } ! 709: ! 710: dmapsize(dmin, dmax) ! 711: int dmin, dmax; ! 712: { ! 713: register int i, blk, size = 0; ! 714: ! 715: blk = dmin; ! 716: for (i = 0; i < NDMAP; i++) { ! 717: size += blk; ! 718: if (blk < dmax) ! 719: blk *= 2; ! 720: } ! 721: return (dtob(size)); ! 722: } ! 723: ! 724: int pushes; ! 725: ! 726: #define FRONT 1 ! 727: #define BACK 2 ! 728: ! 729: /* ! 730: * The page out daemon, which runs as process 2. ! 731: * ! 732: * As long as there are at least lotsfree pages, ! 733: * this process is not run. When the number of free ! 734: * pages stays in the range desfree to lotsfree, ! 735: * this daemon runs through the pages in the loop ! 736: * at a rate determined in vmsched(). Pageout manages ! 737: * two hands on the clock. The front hand moves through ! 738: * memory, clearing the valid bit (simulating a reference bit), ! 739: * and stealing pages from procs that are over maxrss. ! 740: * The back hand travels a distance behind the front hand, ! 741: * freeing the pages that have not been referenced in the time ! 742: * since the front hand passed. If modified, they are pushed to ! 743: * swap before being freed. ! 744: */ ! 745: pageout() ! 746: { ! 747: register int count; ! 748: register int maxhand = pgtocm(maxfree); ! 749: register int fronthand, backhand; ! 750: ! 751: /* ! 752: * Set the two clock hands to be separated by a reasonable amount, ! 753: * but no more than 360 degrees apart. ! 754: */ ! 755: backhand = 0 / CLBYTES; ! 756: fronthand = HANDSPREAD / CLBYTES; ! 757: if (fronthand >= maxhand) ! 758: fronthand = maxhand - 1; ! 759: ! 760: loop: ! 761: /* ! 762: * Before sleeping, look to see if there are any swap I/O headers ! 763: * in the ``cleaned'' list that correspond to dirty ! 764: * pages that have been pushed asynchronously. If so, ! 765: * empty the list by calling cleanup(). ! 766: * ! 767: * N.B.: We guarantee never to block while the cleaned list is nonempty. ! 768: */ ! 769: (void) splbio(); ! 770: if (bclnlist != NULL) { ! 771: (void) spl0(); ! 772: cleanup(); ! 773: goto loop; ! 774: } ! 775: sleep((caddr_t)&proc[2], PSWP+1); ! 776: (void) spl0(); ! 777: count = 0; ! 778: pushes = 0; ! 779: while (nscan < desscan && freemem < lotsfree) { ! 780: /* ! 781: * If checkpage manages to add a page to the free list, ! 782: * we give ourselves another couple of trips around the loop. ! 783: */ ! 784: if (checkpage(fronthand, FRONT)) ! 785: count = 0; ! 786: if (checkpage(backhand, BACK)) ! 787: count = 0; ! 788: cnt.v_scan++; ! 789: nscan++; ! 790: if (++backhand >= maxhand) ! 791: backhand = 0; ! 792: if (++fronthand >= maxhand) { ! 793: fronthand = 0; ! 794: cnt.v_rev++; ! 795: if (count > 2) { ! 796: /* ! 797: * Extremely unlikely, but we went around ! 798: * the loop twice and didn't get anywhere. ! 799: * Don't cycle, stop till the next clock tick. ! 800: */ ! 801: goto loop; ! 802: } ! 803: count++; ! 804: } ! 805: } ! 806: goto loop; ! 807: } ! 808: ! 809: /* ! 810: * An iteration of the clock pointer (hand) around the loop. ! 811: * Look at the page at hand. If it is a ! 812: * locked (for physical i/o e.g.), system (u., page table) ! 813: * or free, then leave it alone. ! 814: * Otherwise, if we are running the front hand, ! 815: * invalidate the page for simulation of the reference bit. ! 816: * If the proc is over maxrss, we take it. ! 817: * If running the back hand, check whether the page ! 818: * has been reclaimed. If not, free the page, ! 819: * pushing it to disk first if necessary. ! 820: */ ! 821: checkpage(hand, whichhand) ! 822: int hand, whichhand; ! 823: { ! 824: register struct proc *rp; ! 825: register struct text *xp; ! 826: register struct cmap *c; ! 827: register struct pte *pte; ! 828: swblk_t daddr; ! 829: unsigned v; ! 830: int klsize; ! 831: ! 832: top: ! 833: /* ! 834: * Find a process and text pointer for the ! 835: * page, and a virtual page number in either the ! 836: * process or the text image. ! 837: */ ! 838: c = &cmap[hand]; ! 839: if (c->c_lock || c->c_free) ! 840: return (0); ! 841: switch (c->c_type) { ! 842: ! 843: case CSYS: ! 844: return (0); ! 845: ! 846: case CTEXT: ! 847: xp = &text[c->c_ndx]; ! 848: rp = xp->x_caddr; ! 849: v = tptov(rp, c->c_page); ! 850: pte = tptopte(rp, c->c_page); ! 851: break; ! 852: ! 853: case CDATA: ! 854: case CSTACK: ! 855: rp = &proc[c->c_ndx]; ! 856: while (rp->p_flag & SNOVM) ! 857: rp = rp->p_xlink; ! 858: xp = rp->p_textp; ! 859: if (c->c_type == CDATA) { ! 860: v = dptov(rp, c->c_page); ! 861: pte = dptopte(rp, c->c_page); ! 862: } else { ! 863: v = sptov(rp, c->c_page); ! 864: pte = sptopte(rp, c->c_page); ! 865: } ! 866: break; ! 867: } ! 868: if (pte->pg_pfnum != cmtopg(hand)) ! 869: panic("bad c_page"); ! 870: #ifdef REFBIT ! 871: /* ! 872: * If any processes attached to the text page have used ! 873: * it, then mark this one used and on the following ! 874: * distpte, they will all be marked used. ! 875: */ ! 876: if (c->c_type == CTEXT && tanyu(xp, vtotp(rp, v))) ! 877: pte->pg_u = 1; ! 878: /* ! 879: * If page is referenced, clear its reference bit. ! 880: * If page is not referenced, clear valid bit ! 881: * and add it to the free list. ! 882: */ ! 883: uncachecl(pte); ! 884: if (anycl(pte, pg_u)) ! 885: #else ! 886: /* ! 887: * If page is valid; make invalid but reclaimable. ! 888: * If this pte is not valid, then it must be reclaimable ! 889: * and we can add it to the free list. ! 890: */ ! 891: if (pte->pg_v) ! 892: #endif ! 893: { ! 894: if (whichhand == BACK) ! 895: return (0); ! 896: #ifdef REFBIT ! 897: pte->pg_u = 0; ! 898: #else ! 899: pte->pg_v = 0; ! 900: rp->p_flag |= SPTECHG; ! 901: #endif ! 902: if (anycl(pte, pg_m)) ! 903: pte->pg_m = 1; ! 904: distcl(pte); ! 905: if (c->c_type == CTEXT) ! 906: distpte(xp, (unsigned)vtotp(rp, v), pte); ! 907: if ((rp->p_flag & (SSEQL|SUANOM)) == 0 && ! 908: rp->p_rssize <= rp->p_maxrss) ! 909: return (0); ! 910: } ! 911: if (c->c_type != CTEXT) { ! 912: /* ! 913: * Guarantee a minimal investment in data ! 914: * space for jobs in balance set. ! 915: */ ! 916: if (rp->p_rssize < saferss - rp->p_slptime) ! 917: return (0); ! 918: } ! 919: ! 920: /* ! 921: * If the page is currently dirty, we ! 922: * have to arrange to have it cleaned before it ! 923: * can be freed. We mark it clean immediately. ! 924: * If it is reclaimed while being pushed, then modified ! 925: * again, we are assured of the correct order of ! 926: * writes because we lock the page during the write. ! 927: * This guarantees that a swap() of this process (and ! 928: * thus this page), initiated in parallel, will, ! 929: * in fact, push the page after us. ! 930: * ! 931: * The most general worst case here would be for ! 932: * a reclaim, a modify and a swapout to occur ! 933: * all before the single page transfer completes. ! 934: */ ! 935: if (dirtycl(pte)) { ! 936: /* ! 937: * If the process is being swapped out ! 938: * or about to exit, do not bother with its ! 939: * dirty pages ! 940: */ ! 941: if (rp->p_flag & (SLOCK|SWEXIT)) ! 942: return (0); ! 943: /* ! 944: * Limit pushes to avoid saturating ! 945: * pageout device. ! 946: */ ! 947: if (pushes > maxpgio / RATETOSCHEDPAGING) ! 948: return (0); ! 949: pushes++; ! 950: ! 951: /* ! 952: * Now carefully make sure that there will ! 953: * be a header available for the push so that ! 954: * we will not block waiting for a header in ! 955: * swap(). The reason this is important is ! 956: * that we (proc[2]) are the one who cleans ! 957: * dirty swap headers and we could otherwise ! 958: * deadlock waiting for ourselves to clean ! 959: * swap headers. The sleep here on &proc[2] ! 960: * is actually (effectively) a sleep on both ! 961: * ourselves and &bswlist, and this is known ! 962: * to swdone and swap in vm_swp.c. That is, ! 963: * &proc[2] will be awakened both when dirty ! 964: * headers show up and also to get the pageout ! 965: * daemon moving. ! 966: */ ! 967: loop2: ! 968: (void) splbio(); ! 969: if (bclnlist != NULL) { ! 970: (void) spl0(); ! 971: cleanup(); ! 972: goto loop2; ! 973: } ! 974: if (bswlist.av_forw == NULL) { ! 975: bswlist.b_flags |= B_WANTED; ! 976: sleep((caddr_t)&proc[2], PSWP+2); ! 977: (void) spl0(); ! 978: /* ! 979: * Page disposition may have changed ! 980: * since process may have exec'ed, ! 981: * forked, exited or just about ! 982: * anything else... try this page ! 983: * frame again, from the top. ! 984: */ ! 985: goto top; ! 986: } ! 987: (void) spl0(); ! 988: ! 989: MLOCK(c); ! 990: uaccess(rp, Pushmap, &pushutl); ! 991: /* ! 992: * Now committed to pushing the page... ! 993: */ ! 994: #ifdef REFBIT ! 995: pte->pg_v = 0; ! 996: rp->p_flag |= SPTECHG; ! 997: #endif ! 998: pte->pg_m = 0; ! 999: distcl(pte); ! 1000: if (c->c_type == CTEXT) { ! 1001: xp->x_poip++; ! 1002: distpte(xp, (unsigned)vtotp(rp, v), pte); ! 1003: } else ! 1004: rp->p_poip++; ! 1005: v = kluster(rp, v, pte, B_WRITE, &klsize, klout, (daddr_t)0); ! 1006: if (klsize == 0) ! 1007: panic("pageout klsize"); ! 1008: daddr = vtod(rp, v, &pushutl.u_dmap, &pushutl.u_smap); ! 1009: (void) swap(rp, daddr, ptob(v), klsize * ctob(CLSIZE), ! 1010: B_WRITE, B_DIRTY, swapdev_vp, pte->pg_pfnum); ! 1011: /* ! 1012: * The cleaning of this page will be ! 1013: * completed later, in cleanup() called ! 1014: * (synchronously) by us (proc[2]). In ! 1015: * the meantime, the page frame is locked ! 1016: * so no havoc can result. ! 1017: */ ! 1018: return (1); /* well, it'll be free soon */ ! 1019: } ! 1020: /* ! 1021: * Propagate valid bit changes. ! 1022: * Decrement the resident set size of the current ! 1023: * text object/process, and put the page in the ! 1024: * free list. Don't detach the page yet; ! 1025: * it may yet have a chance to be reclaimed from ! 1026: * the free list. ! 1027: */ ! 1028: #ifdef REFBIT ! 1029: pte->pg_v = 0; ! 1030: distcl(pte); ! 1031: if (c->c_type == CTEXT) ! 1032: distpte(xp, (unsigned)vtotp(rp, v), pte); ! 1033: else ! 1034: rp->p_flag |= SPTECHG; ! 1035: #endif ! 1036: if (c->c_gone == 0) ! 1037: if (c->c_type == CTEXT) ! 1038: xp->x_rssize -= CLSIZE; ! 1039: else ! 1040: rp->p_rssize -= CLSIZE; ! 1041: memfree(pte, CLSIZE, 0); ! 1042: cnt.v_dfree += CLSIZE; ! 1043: return (1); /* freed a page! */ ! 1044: } ! 1045: ! 1046: /* ! 1047: * Process the ``cleaned'' list. ! 1048: * ! 1049: * Scan through the linked list of swap I/O headers ! 1050: * and free the corresponding pages that have been ! 1051: * cleaned by being written back to the paging area. ! 1052: * If the page has been reclaimed during this time, ! 1053: * we do not free the page. As they are processed, ! 1054: * the swap I/O headers are removed from the cleaned ! 1055: * list and inserted into the free list. ! 1056: */ ! 1057: cleanup() ! 1058: { ! 1059: register struct buf *bp; ! 1060: register struct proc *rp; ! 1061: register struct text *xp; ! 1062: register struct cmap *c; ! 1063: register struct pte *pte; ! 1064: struct pte *upte; ! 1065: unsigned pf; ! 1066: register int i; ! 1067: int s, center; ! 1068: ! 1069: for (;;) { ! 1070: s = splbio(); ! 1071: if ((bp = bclnlist) == 0) ! 1072: break; ! 1073: bclnlist = bp->av_forw; ! 1074: splx(s); ! 1075: pte = vtopte(&proc[2], btop(bp->b_un.b_addr)); ! 1076: center = 0; ! 1077: for (i = 0; i < bp->b_bcount; i += CLSIZE * NBPG) { ! 1078: pf = pte->pg_pfnum; ! 1079: c = &cmap[pgtocm(pf)]; ! 1080: MUNLOCK(c); ! 1081: if (pf != bp->b_pfcent) { ! 1082: if (c->c_gone) { ! 1083: memfree(pte, CLSIZE, 0); ! 1084: cnt.v_dfree += CLSIZE; ! 1085: } ! 1086: goto skip; ! 1087: } ! 1088: center++; ! 1089: switch (c->c_type) { ! 1090: ! 1091: case CSYS: ! 1092: panic("cleanup CSYS"); ! 1093: ! 1094: case CTEXT: ! 1095: xp = &text[c->c_ndx]; ! 1096: xp->x_poip--; ! 1097: if (xp->x_poip == 0) ! 1098: wakeup((caddr_t)&xp->x_poip); ! 1099: break; ! 1100: ! 1101: case CDATA: ! 1102: case CSTACK: ! 1103: rp = &proc[c->c_ndx]; ! 1104: while (rp->p_flag & SNOVM) ! 1105: rp = rp->p_xlink; ! 1106: rp->p_poip--; ! 1107: if (rp->p_poip == 0) ! 1108: wakeup((caddr_t)&rp->p_poip); ! 1109: break; ! 1110: } ! 1111: if (c->c_gone == 0) { ! 1112: switch (c->c_type) { ! 1113: ! 1114: case CTEXT: ! 1115: upte = tptopte(xp->x_caddr, c->c_page); ! 1116: break; ! 1117: ! 1118: case CDATA: ! 1119: upte = dptopte(rp, c->c_page); ! 1120: break; ! 1121: ! 1122: case CSTACK: ! 1123: upte = sptopte(rp, c->c_page); ! 1124: break; ! 1125: } ! 1126: if (upte->pg_v) ! 1127: goto skip; ! 1128: if (c->c_type == CTEXT) ! 1129: xp->x_rssize -= CLSIZE; ! 1130: else ! 1131: rp->p_rssize -= CLSIZE; ! 1132: } ! 1133: memfree(pte, CLSIZE, 0); ! 1134: cnt.v_dfree += CLSIZE; ! 1135: skip: ! 1136: pte += CLSIZE; ! 1137: } ! 1138: if (center != 1) ! 1139: panic("cleanup center"); ! 1140: bp->b_flags = 0; ! 1141: bp->av_forw = bswlist.av_forw; ! 1142: bswlist.av_forw = bp; ! 1143: if (bp->b_vp) ! 1144: brelvp(bp); ! 1145: if (bswlist.b_flags & B_WANTED) { ! 1146: bswlist.b_flags &= ~B_WANTED; ! 1147: wakeup((caddr_t)&bswlist); ! 1148: } ! 1149: } ! 1150: splx(s); ! 1151: } ! 1152: ! 1153: /* ! 1154: * Kluster locates pages adjacent to the argument pages ! 1155: * that are immediately available to include in the pagein/pageout, ! 1156: * and given the availability of memory includes them. ! 1157: * It knows that the process image is contiguous in chunks; ! 1158: * an assumption here is that CLSIZE * KLMAX is a divisor of dmmin, ! 1159: * so that by looking at KLMAX chunks of pages, all such will ! 1160: * necessarily be mapped swap contiguous. ! 1161: */ ! 1162: int noklust; ! 1163: int klicnt[KLMAX]; ! 1164: int klocnt[KLMAX]; ! 1165: ! 1166: kluster(p, v, pte0, rw, pkl, klsize, bn0) ! 1167: register struct proc *p; ! 1168: unsigned v; ! 1169: struct pte *pte0; ! 1170: int rw; ! 1171: register int *pkl; ! 1172: int klsize; ! 1173: daddr_t bn0; ! 1174: { ! 1175: int type, cl, clmax; ! 1176: int kloff, k, klmax; ! 1177: register struct pte *pte; ! 1178: int klback, klforw; ! 1179: int i; ! 1180: unsigned v0; ! 1181: daddr_t bn; ! 1182: register struct cmap *c; ! 1183: ! 1184: if (rw == B_READ) ! 1185: klicnt[0]++; ! 1186: else ! 1187: klocnt[0]++; ! 1188: *pkl = 1; ! 1189: if (noklust || klsize <= 1 || klsize > KLMAX || (klsize & (klsize - 1))) ! 1190: return (v); ! 1191: if (rw == B_READ && freemem < CLSIZE * KLMAX) ! 1192: return (v); ! 1193: if (isassv(p, v)) { ! 1194: type = CSTACK; ! 1195: cl = vtosp(p, v) / CLSIZE; ! 1196: clmax = p->p_ssize / CLSIZE; ! 1197: } else if (isadsv(p, v)) { ! 1198: type = CDATA; ! 1199: cl = vtodp(p, v) / CLSIZE; ! 1200: clmax = p->p_dsize / CLSIZE; ! 1201: } else { ! 1202: type = CTEXT; ! 1203: cl = vtotp(p, v) / CLSIZE; ! 1204: clmax = p->p_textp->x_size / CLSIZE; ! 1205: } ! 1206: kloff = cl & (klsize - 1); ! 1207: pte = pte0; ! 1208: bn = bn0; ! 1209: for (k = kloff; --k >= 0;) { ! 1210: if (type == CSTACK) ! 1211: pte += CLSIZE; ! 1212: else ! 1213: pte -= CLSIZE; ! 1214: if (type == CTEXT && rw == B_READ && bn) { ! 1215: bn -= btodb(CLBYTES); ! 1216: if (mfind(swapdev_vp, bn)) ! 1217: break; ! 1218: } ! 1219: if (!klok(pte, rw)) ! 1220: break; ! 1221: } ! 1222: klback = (kloff - k) - 1; ! 1223: pte = pte0; ! 1224: if ((cl - kloff) + klsize > clmax) ! 1225: klmax = clmax - (cl - kloff); ! 1226: else ! 1227: klmax = klsize; ! 1228: bn = bn0; ! 1229: for (k = kloff; ++k < klmax;) { ! 1230: if (type == CSTACK) ! 1231: pte -= CLSIZE; ! 1232: else ! 1233: pte += CLSIZE; ! 1234: if (type == CTEXT && rw == B_READ && bn) { ! 1235: bn += btodb(CLBYTES); ! 1236: if (mfind(swapdev_vp, bn)) ! 1237: break; ! 1238: } ! 1239: if (!klok(pte, rw)) ! 1240: break; ! 1241: } ! 1242: klforw = (k - kloff) - 1; ! 1243: if (klforw + klback == 0) ! 1244: return (v); ! 1245: pte = pte0; ! 1246: if (type == CSTACK) { ! 1247: pte -= klforw * CLSIZE; ! 1248: v -= klforw * CLSIZE; ! 1249: } else { ! 1250: pte -= klback * CLSIZE; ! 1251: v -= klback * CLSIZE; ! 1252: } ! 1253: *pkl = klforw + klback + 1; ! 1254: if (rw == B_READ) ! 1255: klicnt[0]--, klicnt[*pkl - 1]++; ! 1256: else ! 1257: klocnt[0]--, klocnt[*pkl - 1]++; ! 1258: v0 = v; ! 1259: for (i = 0; i < *pkl; i++) { ! 1260: if (pte == pte0) ! 1261: goto cont; ! 1262: if (rw == B_WRITE) { ! 1263: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 1264: MLOCK(c); ! 1265: pte->pg_m = 0; ! 1266: distcl(pte); ! 1267: if (type == CTEXT) ! 1268: distpte(p->p_textp, (unsigned)vtotp(p, v), pte); ! 1269: } else { ! 1270: struct pte opte; ! 1271: ! 1272: opte = *pte; ! 1273: if (memall(pte, CLSIZE, p, type) == 0) ! 1274: panic("kluster"); ! 1275: pte->pg_prot = opte.pg_prot; ! 1276: cmap[pgtocm(pte->pg_pfnum)].c_intrans = 1; ! 1277: distcl(pte); ! 1278: if (type == CTEXT) { ! 1279: p->p_textp->x_rssize += CLSIZE; ! 1280: distpte(p->p_textp, (unsigned)vtotp(p, v), pte); ! 1281: } else ! 1282: p->p_rssize += CLSIZE; ! 1283: distcl(pte); ! 1284: } ! 1285: cont: ! 1286: pte += CLSIZE; ! 1287: v += CLSIZE; ! 1288: } ! 1289: return (v0); ! 1290: } ! 1291: ! 1292: klok(pte, rw) ! 1293: register struct pte *pte; ! 1294: int rw; ! 1295: { ! 1296: register struct cmap *c; ! 1297: ! 1298: if (rw == B_WRITE) { ! 1299: if (pte->pg_fod) ! 1300: return (0); ! 1301: if (pte->pg_pfnum == 0) ! 1302: return (0); ! 1303: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 1304: if (c->c_lock || c->c_intrans) ! 1305: return (0); ! 1306: uncachecl(pte); ! 1307: if (!dirtycl(pte)) ! 1308: return (0); ! 1309: return (1); ! 1310: } else { ! 1311: if (pte->pg_fod) ! 1312: return (0); ! 1313: if (pte->pg_pfnum) ! 1314: return (0); ! 1315: return (1); ! 1316: } ! 1317: } ! 1318: ! 1319: /* ! 1320: * Fodkluster locates pages adjacent to the argument pages ! 1321: * that are immediately available to include in the pagein, ! 1322: * and given the availability of memory includes them. ! 1323: * It wants to page in a file system block if it can. ! 1324: */ ! 1325: int nofodklust = 0; ! 1326: int fodklcnt[KLMAX]; ! 1327: ! 1328: fodkluster(p, v0, pte0, pkl, vp, pbn) ! 1329: register struct proc *p; ! 1330: unsigned v0; ! 1331: struct pte *pte0; ! 1332: int *pkl; ! 1333: struct vnode *vp; ! 1334: daddr_t *pbn; ! 1335: { ! 1336: register struct pte *pte; ! 1337: register struct fpte *fpte; ! 1338: register daddr_t bn; ! 1339: daddr_t bnswap; ! 1340: unsigned v, vmin, vmax; ! 1341: register int klsize; ! 1342: int klback, type, i; ! 1343: ! 1344: fodklcnt[0]++; ! 1345: *pkl = 1; ! 1346: if (freemem < KLMAX || nofodklust) ! 1347: return (v0); ! 1348: if (isatsv(p, v0)) { ! 1349: type = CTEXT; ! 1350: vmin = tptov(p, 0); ! 1351: vmax = tptov(p, clrnd(p->p_tsize) - CLSIZE); ! 1352: } else { ! 1353: type = CDATA; ! 1354: vmin = dptov(p, 0); ! 1355: vmax = dptov(p, clrnd(p->p_dsize) - CLSIZE); ! 1356: } ! 1357: fpte = (struct fpte *)pte0; ! 1358: bn = *pbn; ! 1359: v = v0; ! 1360: for (klsize = 1; klsize < KLMAX; klsize++) { ! 1361: if (v <= vmin) ! 1362: break; ! 1363: v -= CLSIZE; ! 1364: fpte -= CLSIZE; ! 1365: if (fpte->pg_fod == 0) ! 1366: break; ! 1367: bn -= btodb(CLBYTES); ! 1368: if (fpte->pg_blkno != bn) ! 1369: break; ! 1370: if (type == CTEXT) { ! 1371: if (mfind(vp, bn)) ! 1372: break; ! 1373: /* ! 1374: * Flush any previous text page use of this ! 1375: * swap device block. ! 1376: */ ! 1377: bnswap = vtod(p, v, &u.u_dmap, &u.u_smap); ! 1378: munhash(swapdev_vp, bnswap); ! 1379: } ! 1380: } ! 1381: klback = klsize - 1; ! 1382: fpte = (struct fpte *)pte0; ! 1383: bn = *pbn; ! 1384: v = v0; ! 1385: for (; klsize < KLMAX; klsize++) { ! 1386: v += CLSIZE; ! 1387: if (v > vmax) ! 1388: break; ! 1389: fpte += CLSIZE; ! 1390: if (fpte->pg_fod == 0) ! 1391: break; ! 1392: bn += btodb(CLBYTES); ! 1393: if (fpte->pg_blkno != bn) ! 1394: break; ! 1395: if (type == CTEXT) { ! 1396: if (mfind(vp, bn)) ! 1397: break; ! 1398: /* ! 1399: * Flush any previous text page use of this ! 1400: * swap device block. ! 1401: */ ! 1402: bnswap = vtod(p, v, &u.u_dmap, &u.u_smap); ! 1403: munhash(swapdev_vp, bnswap); ! 1404: } ! 1405: } ! 1406: if (klsize == 1) ! 1407: return (v0); ! 1408: pte = pte0; ! 1409: pte -= klback * CLSIZE; ! 1410: v0 -= klback * CLSIZE; ! 1411: *pbn -= klback * btodb(CLBYTES); ! 1412: *pkl = klsize; ! 1413: fodklcnt[0]--; fodklcnt[klsize - 1]++; ! 1414: v = v0; ! 1415: for (i = 0; i < klsize; i++) { ! 1416: if (pte != pte0) { ! 1417: struct pte opte; ! 1418: int pf; ! 1419: ! 1420: opte = *pte; ! 1421: if (memall(pte, CLSIZE, p, type) == 0) ! 1422: panic("fodkluster"); ! 1423: pte->pg_prot = opte.pg_prot; ! 1424: pf = pte->pg_pfnum; ! 1425: pte->pg_m = 1; ! 1426: cmap[pgtocm(pf)].c_intrans = 1; ! 1427: distcl(pte); ! 1428: if (type == CTEXT) { ! 1429: p->p_textp->x_rssize += CLSIZE; ! 1430: distpte(p->p_textp, (unsigned)vtotp(p, v), pte); ! 1431: } else ! 1432: p->p_rssize += CLSIZE; ! 1433: distcl(pte); ! 1434: } ! 1435: pte += CLSIZE; ! 1436: v += CLSIZE; ! 1437: } ! 1438: return (v0); ! 1439: } ! 1440: ! 1441: #ifdef REFBIT ! 1442: /* ! 1443: * Examine the reference bits in the pte's of all ! 1444: * processes linked to a particular text segment. ! 1445: */ ! 1446: tanyu(xp, tp) ! 1447: struct text *xp; ! 1448: register tp; ! 1449: { ! 1450: register struct proc *p; ! 1451: register struct pte *pte; ! 1452: ! 1453: for (p = xp->x_caddr; p; p = p->p_xlink) { ! 1454: pte = tptopte(p, tp); ! 1455: uncache(pte); ! 1456: if (anycl(pte, pg_u)) ! 1457: return (1); ! 1458: } ! 1459: return (0); ! 1460: } ! 1461: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.