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