|
|
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_mem.c 7.15 (Berkeley) 6/28/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "cmap.h" ! 26: #include "user.h" ! 27: #include "proc.h" ! 28: #include "text.h" ! 29: #include "vm.h" ! 30: #include "buf.h" ! 31: #include "vnode.h" ! 32: #include "mount.h" ! 33: #include "trace.h" ! 34: ! 35: #include "machine/pte.h" ! 36: ! 37: /* ! 38: * Allocate memory, and always succeed ! 39: * by jolting page-out daemon ! 40: * so as to obtain page frames. ! 41: * To be used in conjunction with vmemfree(). ! 42: */ ! 43: vmemall(pte, size, p, type) ! 44: register struct pte *pte; ! 45: int size; ! 46: struct proc *p; ! 47: { ! 48: register int m; ! 49: ! 50: if (size <= 0 || size > maxmem) ! 51: panic("vmemall size"); ! 52: while (size > 0) { ! 53: if (freemem < desfree) ! 54: outofmem(); ! 55: while (freemem == 0) ! 56: sleep((caddr_t)&freemem, PSWP+2); ! 57: m = imin(size, freemem); ! 58: (void) memall(pte, m, p, type); ! 59: size -= m; ! 60: pte += m; ! 61: } ! 62: if (freemem < desfree) ! 63: outofmem(); ! 64: /* ! 65: * Always succeeds, but return success for ! 66: * vgetu and vgetpt (e.g.) which call either ! 67: * memall or vmemall depending on context. ! 68: */ ! 69: return (1); ! 70: } ! 71: ! 72: /* ! 73: * Free valid and reclaimable page frames belonging to the ! 74: * count pages starting at pte. If a page is valid ! 75: * or reclaimable and locked (but not a system page), then ! 76: * we simply mark the page as c_gone and let the pageout ! 77: * daemon free the page when it is through with it. ! 78: * If a page is reclaimable, and already in the free list, then ! 79: * we mark the page as c_gone, and (of course) don't free it. ! 80: * ! 81: * Determines the largest contiguous cluster of ! 82: * valid pages and frees them in one call to memfree. ! 83: */ ! 84: vmemfree(pte, count) ! 85: register struct pte *pte; ! 86: register int count; ! 87: { ! 88: register struct cmap *c; ! 89: register struct pte *spte; ! 90: register int j; ! 91: int size, pcnt; ! 92: #ifdef notdef ! 93: int fileno; ! 94: #endif ! 95: ! 96: if (count % CLSIZE) ! 97: panic("vmemfree"); ! 98: for (size = 0, pcnt = 0; count > 0; pte += CLSIZE, count -= CLSIZE) { ! 99: if (pte->pg_fod == 0 && pte->pg_pfnum) { ! 100: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 101: pcnt += CLSIZE; ! 102: if (c->c_lock && c->c_type != CSYS) { ! 103: for (j = 0; j < CLSIZE; j++) ! 104: *(int *)(pte+j) &= PG_PROT; ! 105: c->c_gone = 1; ! 106: goto free; ! 107: } ! 108: if (c->c_free) { ! 109: pcnt -= CLSIZE; ! 110: for (j = 0; j < CLSIZE; j++) ! 111: *(int *)(pte+j) &= PG_PROT; ! 112: if (c->c_type == CTEXT) ! 113: distpte(&text[c->c_ndx], c->c_page, ! 114: pte); ! 115: c->c_gone = 1; ! 116: goto free; ! 117: } ! 118: if (size == 0) ! 119: spte = pte; ! 120: size += CLSIZE; ! 121: continue; ! 122: } ! 123: #ifdef notdef ! 124: /* Don't do anything with mapped ptes */ ! 125: if (pte->pg_fod && pte->pg_v) ! 126: goto free; ! 127: #endif ! 128: if (pte->pg_fod) { ! 129: #ifdef notdef ! 130: fileno = ((struct fpte *)pte)->pg_fileno; ! 131: if (fileno < NOFILE) ! 132: panic("vmemfree vread"); ! 133: #endif ! 134: for (j = 0; j < CLSIZE; j++) ! 135: *(int *)(pte+j) &= PG_PROT; ! 136: } ! 137: free: ! 138: if (size) { ! 139: memfree(spte, size, 1); ! 140: size = 0; ! 141: } ! 142: } ! 143: if (size) ! 144: memfree(spte, size, 1); ! 145: return (pcnt); ! 146: } ! 147: ! 148: /* ! 149: * Unlink a page frame from the free list - ! 150: * ! 151: * Performed if the page being reclaimed ! 152: * is in the free list. ! 153: */ ! 154: munlink(c) ! 155: register struct cmap *c; ! 156: { ! 157: register int next, prev; ! 158: ! 159: next = c->c_next; ! 160: prev = c->c_prev; ! 161: cmap[prev].c_next = next; ! 162: cmap[next].c_prev = prev; ! 163: c->c_free = 0; ! 164: if (freemem < minfree) ! 165: outofmem(); ! 166: freemem -= CLSIZE; ! 167: } ! 168: ! 169: /* ! 170: * Allocate memory - ! 171: * ! 172: * The free list appears as a doubly linked list ! 173: * in the core map with cmap[0] serving as a header. ! 174: */ ! 175: memall(pte, size, p, type) ! 176: register struct pte *pte; ! 177: int size; ! 178: struct proc *p; ! 179: { ! 180: register struct cmap *c; ! 181: register struct pte *rpte; ! 182: register struct proc *rp; ! 183: int i, j, next, curpos; ! 184: unsigned pf; ! 185: struct cmap *c1, *c2; ! 186: int s; ! 187: ! 188: if (size % CLSIZE) ! 189: panic("memall"); ! 190: s = splimp(); ! 191: if (size > freemem) { ! 192: splx(s); ! 193: return (0); ! 194: } ! 195: trace(TR_MALL, size, u.u_procp->p_pid); ! 196: for (i = size; i > 0; i -= CLSIZE) { ! 197: curpos = cmap[CMHEAD].c_next; ! 198: c = &cmap[curpos]; ! 199: freemem -= CLSIZE; ! 200: next = c->c_next; ! 201: cmap[CMHEAD].c_next = next; ! 202: cmap[next].c_prev = CMHEAD; ! 203: if (c->c_free == 0) ! 204: panic("dup mem alloc"); ! 205: if (cmtopg(curpos) > maxfree) ! 206: panic("bad mem alloc"); ! 207: if (c->c_gone == 0 && c->c_type != CSYS) { ! 208: if (c->c_type == CTEXT) ! 209: rp = text[c->c_ndx].x_caddr; ! 210: else ! 211: rp = &proc[c->c_ndx]; ! 212: while (rp->p_flag & SNOVM) ! 213: rp = rp->p_xlink; ! 214: switch (c->c_type) { ! 215: ! 216: case CTEXT: ! 217: rpte = tptopte(rp, c->c_page); ! 218: break; ! 219: ! 220: case CDATA: ! 221: rpte = dptopte(rp, c->c_page); ! 222: break; ! 223: ! 224: case CSTACK: ! 225: rpte = sptopte(rp, c->c_page); ! 226: break; ! 227: } ! 228: zapcl(rpte, pg_pfnum) = 0; ! 229: if (c->c_type == CTEXT) ! 230: distpte(&text[c->c_ndx], c->c_page, rpte); ! 231: } ! 232: switch (type) { ! 233: ! 234: case CSYS: ! 235: c->c_ndx = p->p_ndx; ! 236: break; ! 237: ! 238: case CTEXT: ! 239: c->c_page = vtotp(p, ptetov(p, pte)); ! 240: c->c_ndx = p->p_textp - &text[0]; ! 241: break; ! 242: ! 243: case CDATA: ! 244: c->c_page = vtodp(p, ptetov(p, pte)); ! 245: c->c_ndx = p->p_ndx; ! 246: break; ! 247: ! 248: case CSTACK: ! 249: c->c_page = vtosp(p, ptetov(p, pte)); ! 250: c->c_ndx = p->p_ndx; ! 251: break; ! 252: } ! 253: if (c->c_blkno) { ! 254: /* ! 255: * This is very like munhash(), except ! 256: * that we really don't want to bother ! 257: * to calculate a vp to pass to it. ! 258: */ ! 259: j = CMHASH(c->c_blkno); ! 260: c1 = &cmap[cmhash[j]]; ! 261: if (c1 == c) ! 262: cmhash[j] = c1->c_hlink; ! 263: else { ! 264: for (;;) { ! 265: if (c1 == ecmap) ! 266: panic("memall ecmap"); ! 267: c2 = c1; ! 268: c1 = &cmap[c2->c_hlink]; ! 269: if (c1 == c) ! 270: break; ! 271: } ! 272: c2->c_hlink = c1->c_hlink; ! 273: } ! 274: if (mfind(c->c_vp, (daddr_t)(u_long)c->c_blkno)) ! 275: panic("memall mfind"); ! 276: HOLDRELE(c1->c_vp); ! 277: c1->c_vp = NULLVP; ! 278: c1->c_blkno = 0; ! 279: c1->c_hlink = 0; ! 280: } ! 281: pf = cmtopg(curpos); ! 282: for (j = 0; j < CLSIZE; j++) { ! 283: *(int *)pte = 0; ! 284: pte++->pg_pfnum = pf++; ! 285: } ! 286: c->c_free = 0; ! 287: c->c_gone = 0; ! 288: if (c->c_intrans || c->c_want) ! 289: panic("memall intrans|want"); ! 290: c->c_lock = 1; ! 291: c->c_type = type; ! 292: } ! 293: splx(s); ! 294: return (size); ! 295: } ! 296: ! 297: /* ! 298: * Free memory - ! 299: * ! 300: * The page frames being returned are inserted ! 301: * to the head/tail of the free list depending ! 302: * on whether there is any possible future use of them. ! 303: * ! 304: * If the freemem count had been zero, ! 305: * the processes sleeping for memory ! 306: * are awakened. ! 307: */ ! 308: memfree(pte, size, detach) ! 309: register struct pte *pte; ! 310: register int size; ! 311: { ! 312: register int i, j, prev, next; ! 313: register struct cmap *c; ! 314: int s; ! 315: ! 316: if (size % CLSIZE) ! 317: panic("memfree"); ! 318: if (freemem < CLSIZE * KLMAX) ! 319: wakeup((caddr_t)&freemem); ! 320: while (size > 0) { ! 321: size -= CLSIZE; ! 322: i = pte->pg_pfnum; ! 323: if (i < firstfree || i > maxfree) ! 324: panic("bad mem free"); ! 325: i = pgtocm(i); ! 326: c = &cmap[i]; ! 327: if (c->c_free) ! 328: panic("dup mem free"); ! 329: if (detach && c->c_type != CSYS) { ! 330: for (j = 0; j < CLSIZE; j++) ! 331: *(int *)(pte+j) &= PG_PROT; ! 332: c->c_gone = 1; ! 333: } ! 334: s = splimp(); ! 335: if (detach && c->c_blkno == 0) { ! 336: next = cmap[CMHEAD].c_next; ! 337: cmap[next].c_prev = i; ! 338: c->c_prev = CMHEAD; ! 339: c->c_next = next; ! 340: cmap[CMHEAD].c_next = i; ! 341: } else { ! 342: prev = cmap[CMHEAD].c_prev; ! 343: cmap[prev].c_next = i; ! 344: c->c_next = CMHEAD; ! 345: c->c_prev = prev; ! 346: cmap[CMHEAD].c_prev = i; ! 347: } ! 348: c->c_free = 1; ! 349: freemem += CLSIZE; ! 350: splx(s); ! 351: pte += CLSIZE; ! 352: } ! 353: } ! 354: ! 355: /* ! 356: * Enter clist block c on the hash chains. ! 357: * It contains file system block bn from vnode vp. ! 358: */ ! 359: mhash(c, vp, bn) ! 360: register struct cmap *c; ! 361: struct vnode *vp; ! 362: daddr_t bn; ! 363: { ! 364: register int i = CMHASH(bn); ! 365: ! 366: c->c_hlink = cmhash[i]; ! 367: cmhash[i] = c - cmap; ! 368: c->c_blkno = bn; ! 369: c->c_vp = vp; ! 370: VHOLD(vp); ! 371: } ! 372: ! 373: /* ! 374: * Pull the clist entry of <vp,bn> off the hash chains ! 375: * if present. ! 376: */ ! 377: munhash(vp, bn) ! 378: struct vnode *vp; ! 379: daddr_t bn; ! 380: { ! 381: int i = CMHASH(bn); ! 382: register struct cmap *c1, *c2; ! 383: int s = splimp(); ! 384: ! 385: c1 = &cmap[cmhash[i]]; ! 386: if (c1 == ecmap) ! 387: goto out; ! 388: if (c1->c_blkno == bn && c1->c_vp == vp) ! 389: cmhash[i] = c1->c_hlink; ! 390: else { ! 391: for (;;) { ! 392: c2 = c1; ! 393: c1 = &cmap[c2->c_hlink]; ! 394: if (c1 == ecmap) ! 395: goto out; ! 396: if (c1->c_blkno == bn && c1->c_vp == vp) ! 397: break; ! 398: } ! 399: c2->c_hlink = c1->c_hlink; ! 400: } ! 401: HOLDRELE(vp); ! 402: c1->c_vp = NULLVP; ! 403: c1->c_blkno = 0; ! 404: c1->c_hlink = 0; ! 405: out: ! 406: splx(s); ! 407: } ! 408: ! 409: /* ! 410: * Look for block bn of vnode vp in the free pool. ! 411: * Currently it should not be possible to find it unless it is ! 412: * c_free and c_gone, although this may later not be true. ! 413: * (This is because active texts are locked against file system ! 414: * writes by the system.) ! 415: */ ! 416: struct cmap * ! 417: mfind(vp, bn) ! 418: struct vnode *vp; ! 419: daddr_t bn; ! 420: { ! 421: register struct cmap *c1 = &cmap[cmhash[CMHASH(bn)]]; ! 422: int si = splimp(); ! 423: ! 424: while (c1 != ecmap) { ! 425: if (c1->c_blkno == bn && c1->c_vp == vp) { ! 426: splx(si); ! 427: return (c1); ! 428: } ! 429: c1 = &cmap[c1->c_hlink]; ! 430: } ! 431: splx(si); ! 432: return ((struct cmap *)0); ! 433: } ! 434: ! 435: /* ! 436: * Purge blocks from vnode vp from incore cache ! 437: * before umount(). ! 438: */ ! 439: mpurge(vp) ! 440: struct vnode *vp; ! 441: { ! 442: register struct cmap *c1, *c2; ! 443: register int i; ! 444: int relcnt = 0, si = splimp(); ! 445: ! 446: for (i = 0; i < CMHSIZ; i++) { ! 447: more: ! 448: c1 = &cmap[cmhash[i]]; ! 449: if (c1 == ecmap) ! 450: continue; ! 451: if (c1->c_vp == vp) ! 452: cmhash[i] = c1->c_hlink; ! 453: else { ! 454: for (;;) { ! 455: c2 = c1; ! 456: c1 = &cmap[c1->c_hlink]; ! 457: if (c1 == ecmap) ! 458: goto cont; ! 459: if (c1->c_vp == vp) ! 460: break; ! 461: } ! 462: c2->c_hlink = c1->c_hlink; ! 463: } ! 464: relcnt++; ! 465: c1->c_vp = NULLVP; ! 466: c1->c_blkno = 0; ! 467: c1->c_hlink = 0; ! 468: goto more; ! 469: cont: ! 470: ; ! 471: } ! 472: while (relcnt--) ! 473: HOLDRELE(vp); ! 474: splx(si); ! 475: } ! 476: ! 477: /* ! 478: * Purge blocks for filesystem mp from incore cache ! 479: * before umount(). ! 480: */ ! 481: mpurgemp(mp) ! 482: struct mount *mp; ! 483: { ! 484: register struct cmap *c1, *c2; ! 485: register int i; ! 486: int s = splimp(); ! 487: ! 488: more: ! 489: for (i = 0; i < CMHSIZ; i++) { ! 490: c1 = &cmap[cmhash[i]]; ! 491: if (c1 == ecmap) ! 492: continue; ! 493: if (mp == NULL || c1->c_vp->v_mount == mp) ! 494: cmhash[i] = c1->c_hlink; ! 495: else { ! 496: for (;;) { ! 497: c2 = c1; ! 498: c1 = &cmap[c1->c_hlink]; ! 499: if (c1 == ecmap) ! 500: goto cont; ! 501: if (c1->c_vp->v_mount == mp) ! 502: break; ! 503: } ! 504: c2->c_hlink = c1->c_hlink; ! 505: } ! 506: (void) splx(s); ! 507: HOLDRELE(c1->c_vp); ! 508: s = splimp(); ! 509: c1->c_vp = NULLVP; ! 510: c1->c_blkno = 0; ! 511: c1->c_hlink = 0; ! 512: goto more; ! 513: cont: ! 514: ; ! 515: } ! 516: (void) splx(s); ! 517: } ! 518: ! 519: /* ! 520: * Initialize core map ! 521: */ ! 522: meminit(first, last) ! 523: int first, last; ! 524: { ! 525: register int i; ! 526: register struct cmap *c; ! 527: ! 528: firstfree = clrnd(first); ! 529: maxfree = clrnd(last - (CLSIZE - 1)); ! 530: freemem = maxfree - firstfree; ! 531: ecmx = ecmap - cmap; ! 532: if (ecmx < freemem / CLSIZE) ! 533: freemem = ecmx * CLSIZE; ! 534: for (i = 1; i <= freemem / CLSIZE; i++) { ! 535: cmap[i-1].c_next = i; ! 536: c = &cmap[i]; ! 537: c->c_prev = i-1; ! 538: c->c_free = 1; ! 539: c->c_gone = 1; ! 540: c->c_type = CSYS; ! 541: c->c_blkno = 0; ! 542: } ! 543: cmap[freemem / CLSIZE].c_next = CMHEAD; ! 544: for (i = 0; i < CMHSIZ; i++) ! 545: cmhash[i] = ecmx; ! 546: cmap[CMHEAD].c_prev = freemem / CLSIZE; ! 547: cmap[CMHEAD].c_type = CSYS; ! 548: avefree = freemem; ! 549: } ! 550: ! 551: #ifdef notdef ! 552: /* ! 553: * Wait for frame pf to become unlocked ! 554: * if it is currently locked. ! 555: */ ! 556: mwait(c) ! 557: struct cmap *c; ! 558: { ! 559: ! 560: mlock(c); ! 561: munlock(c); ! 562: } ! 563: ! 564: /* ! 565: * Lock a page frame. ! 566: */ ! 567: mlock(c) ! 568: register struct cmap *c; ! 569: { ! 570: ! 571: while (c->c_lock) { ! 572: c->c_want = 1; ! 573: sleep((caddr_t)c, PSWP+1); ! 574: } ! 575: c->c_lock = 1; ! 576: } ! 577: ! 578: /* ! 579: * Unlock a page frame. ! 580: */ ! 581: munlock(c) ! 582: register struct cmap *c; ! 583: { ! 584: ! 585: if (c->c_lock == 0) ! 586: panic("dup page unlock"); ! 587: if (c->c_want) { ! 588: wakeup((caddr_t)c); ! 589: c->c_want = 0; ! 590: } ! 591: c->c_lock = 0; ! 592: } ! 593: #endif ! 594: ! 595: /* ! 596: * Lock a virtual segment. ! 597: * ! 598: * For each cluster of pages, if the cluster is not valid, ! 599: * touch it to fault it in, otherwise just lock page frame. ! 600: * Called from physio to ensure that the pages ! 601: * participating in raw i/o are valid and locked. ! 602: */ ! 603: vslock(base, count) ! 604: caddr_t base; ! 605: { ! 606: register unsigned v; ! 607: register int npf; ! 608: register struct pte *pte; ! 609: register struct cmap *c; ! 610: ! 611: #if defined(tahoe) ! 612: /* ! 613: * TAHOE I/O drivers may arrive here on raw I/O, ! 614: * base will be a system address in this case ! 615: */ ! 616: if (((int)base & KERNBASE) == KERNBASE) /* system addresses */ ! 617: return; ! 618: #endif ! 619: v = clbase(btop(base)); ! 620: pte = vtopte(u.u_procp, v); ! 621: npf = btoc(count + ((int)base & CLOFSET)); ! 622: for (; npf > 0; pte += CLSIZE, v += CLSIZE, npf -= CLSIZE) { ! 623: retry: ! 624: if (pte->pg_v) { ! 625: #ifdef MAPMEM ! 626: if (pte->pg_fod) /* mapped page */ ! 627: continue; ! 628: #endif ! 629: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 630: if (c->c_lock) { ! 631: MLOCK(c); ! 632: MUNLOCK(c); ! 633: goto retry; ! 634: } ! 635: MLOCK(c); ! 636: } else ! 637: pagein(ctob(v), 1); /* return it locked */ ! 638: } ! 639: } ! 640: ! 641: /* ! 642: * Unlock a virtual segment. ! 643: */ ! 644: vsunlock(base, count, rw) ! 645: caddr_t base; ! 646: { ! 647: register struct pte *pte; ! 648: register struct cmap *c; ! 649: unsigned v; ! 650: int npf; ! 651: ! 652: #if defined(tahoe) ! 653: /* ! 654: * TAHOE I/O drivers may arrive here on raw I/O, ! 655: * base will be a system address in this case ! 656: */ ! 657: if (((int)base & KERNBASE) == KERNBASE) /* system addresses */ ! 658: return; ! 659: #endif ! 660: v = clbase(btop(base)); ! 661: pte = vtopte(u.u_procp, v); ! 662: npf = btoc(count + ((int)base & CLOFSET)); ! 663: for (; npf > 0; pte += CLSIZE, npf -= CLSIZE) { ! 664: #ifdef MAPMEM ! 665: if (pte->pg_fod && pte->pg_v) /* mapped page */ ! 666: continue; ! 667: #endif ! 668: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 669: MUNLOCK(c); ! 670: if (rw == B_READ) /* Reading from device writes memory */ ! 671: pte->pg_m = 1; ! 672: } ! 673: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.