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