|
|
1.1 ! root 1: /* vmmem.c 4.7 81/07/09 */ ! 2: ! 3: #include "sys/param.h" ! 4: #include "sys/systm.h" ! 5: #include "sys/pte.h" ! 6: #include "sys/cmap.h" ! 7: #include "sys/user.h" ! 8: #include "sys/proc.h" ! 9: #include "sys/text.h" ! 10: #include "sys/vm.h" ! 11: #include "sys/file.h" ! 12: #include "sys/inode.h" ! 13: #include "sys/buf.h" ! 14: #include "sys/map.h" ! 15: ! 16: /* ! 17: * Shared text pages are not totally abandoned when a process ! 18: * exits, but are remembered while in the free list hashed by <mdev,blkno> ! 19: * off the cmhash structure so that they can be reattached ! 20: * if another instance of the program runs again soon. ! 21: */ ! 22: #define CMHSIZ 512 /* SHOULD BE DYNAMIC */ ! 23: #define CMHASH(bn) ((bn)&(CMHSIZ-1)) ! 24: int cmhash[CMHSIZ]; /* make words big enough for c_hlink */ ! 25: ! 26: /* ! 27: * Allocate memory, and always succeed ! 28: * by jolting page-out daemon ! 29: * so as to obtain page frames. ! 30: * To be used in conjunction with vmemfree(). ! 31: */ ! 32: vmemall(pte, size, p, type) ! 33: register struct pte *pte; ! 34: int size; ! 35: struct proc *p; ! 36: { ! 37: register int m; ! 38: ! 39: if (size <= 0 || size > maxmem) ! 40: panic("vmemall size"); ! 41: while (size > 0) { ! 42: if (freemem < desfree) ! 43: wakeup((caddr_t)&proc[PAGEPID]); /* jolt daemon */ ! 44: while (freemem == 0) ! 45: sleep((caddr_t)&freemem, PSWP+2); ! 46: m = imin(size, freemem); ! 47: (void) memall(pte, m, p, type); ! 48: size -= m; ! 49: pte += m; ! 50: } ! 51: if (freemem < desfree) ! 52: wakeup((caddr_t)&proc[PAGEPID]); /* jolt daemon */ ! 53: /* ! 54: * Always succeeds, but return success for ! 55: * vgetu and vgetpt (e.g.) which call either ! 56: * memall or vmemall depending on context. ! 57: */ ! 58: return (1); ! 59: } ! 60: ! 61: /* ! 62: * Free valid and reclaimable page frames belonging to the ! 63: * count pages starting at pte. If a page is valid ! 64: * or reclaimable and locked (but not a system page), then ! 65: * we simply mark the page as c_gone and let the pageout ! 66: * daemon free the page when it is through with it. ! 67: * If a page is reclaimable, and already in the free list, then ! 68: * we mark the page as c_gone, and (of course) don't free it. ! 69: * ! 70: * Determines the largest contiguous cluster of ! 71: * valid pages and frees them in one call to memfree. ! 72: */ ! 73: vmemfree(pte, count) ! 74: register struct pte *pte; ! 75: register int count; ! 76: { ! 77: register struct cmap *c; ! 78: register struct pte *spte; ! 79: register int j; ! 80: int size, pcnt, fileno; ! 81: ! 82: if (count % CLSIZE) ! 83: panic("vmemfree"); ! 84: for (size = 0, pcnt = 0; count > 0; pte += CLSIZE, count -= CLSIZE) { ! 85: if (pte->pg_fod == 0 && pte->pg_pfnum) { ! 86: c = &cmap[pgtocm(pte->pg_pfnum)]; ! 87: pcnt += CLSIZE; ! 88: if (c->c_lock && c->c_type != CSYS) { ! 89: for (j = 0; j < CLSIZE; j++) ! 90: *(int *)(pte+j) &= (PG_PROT|PG_VREADM); ! 91: c->c_gone = 1; ! 92: goto free; ! 93: } ! 94: if (c->c_free) { ! 95: pcnt -= CLSIZE; ! 96: for (j = 0; j < CLSIZE; j++) ! 97: *(int *)(pte+j) &= (PG_PROT|PG_VREADM); ! 98: if (c->c_type == CTEXT) ! 99: distpte(&text[c->c_ndx], (int)c->c_page, pte); ! 100: c->c_gone = 1; ! 101: goto free; ! 102: } ! 103: if (size == 0) ! 104: spte = pte; ! 105: size += CLSIZE; ! 106: continue; ! 107: } ! 108: if (pte->pg_fod) { ! 109: fileno = ((struct fpte *)pte)->pg_source + PG_FMIN; ! 110: if (fileno > PG_FMAX) ! 111: panic("vmemfree pg_source"); ! 112: if (fileno < NOFILE) ! 113: panic("vmemfree, vrpages ref'd"); ! 114: for (j = 0; j < CLSIZE; j++) ! 115: *(int *)(pte+j) &= (PG_PROT|PG_VREADM); ! 116: } ! 117: free: ! 118: if (size) { ! 119: memfree(spte, size, 1); ! 120: size = 0; ! 121: } ! 122: } ! 123: if (size) ! 124: memfree(spte, size, 1); ! 125: return (pcnt); ! 126: } ! 127: ! 128: /* ! 129: * Unlink a page frame from the free list - ! 130: * ! 131: * Performed if the page being reclaimed ! 132: * is in the free list. ! 133: */ ! 134: munlink(pf) ! 135: unsigned pf; ! 136: { ! 137: register int next, prev; ! 138: ! 139: next = cmap[pgtocm(pf)].c_next; ! 140: prev = cmap[pgtocm(pf)].c_prev; ! 141: cmap[prev].c_next = next; ! 142: cmap[next].c_prev = prev; ! 143: cmap[pgtocm(pf)].c_free = 0; ! 144: if (freemem < minfree) ! 145: wakeup((caddr_t)&proc[PAGEPID]); /* jolt paging daemon */ ! 146: freemem -= CLSIZE; ! 147: } ! 148: ! 149: /* ! 150: * Allocate memory - ! 151: * ! 152: * The free list appears as a doubly linked list ! 153: * in the core map with cmap[0] serving as a header. ! 154: */ ! 155: memall(pte, size, p, type) ! 156: register struct pte *pte; ! 157: int size; ! 158: struct proc *p; ! 159: { ! 160: register struct cmap *c; ! 161: register struct pte *rpte; ! 162: register struct proc *rp; ! 163: register int i, j; ! 164: int px; ! 165: unsigned pf; ! 166: struct cmap *c1, *c2; ! 167: ! 168: if (size % CLSIZE) ! 169: panic("memall"); ! 170: if (size > freemem) ! 171: return (0); ! 172: px = p - proc; ! 173: for (i = size; i > 0; i -= CLSIZE) { ! 174: c = &cmap[cmap[CMHEAD].c_next]; ! 175: if (c->c_free == 0) ! 176: panic("dup mem alloc"); ! 177: if (c->c_gone == 0 && c->c_type != CSYS) { ! 178: if (c->c_type == CTEXT) ! 179: rp = text[c->c_ndx].x_caddr; ! 180: else ! 181: rp = &proc[c->c_ndx]; ! 182: switch (c->c_type) { ! 183: ! 184: case CTEXT: ! 185: rpte = tptopte(rp, c->c_page); ! 186: break; ! 187: ! 188: case CDATA: ! 189: rpte = dptopte(rp, c->c_page); ! 190: break; ! 191: ! 192: case CSTACK: ! 193: rpte = sptopte(rp, c->c_page); ! 194: break; ! 195: } ! 196: zapcl(rpte, pg_pfnum) = 0; ! 197: if (c->c_type == CTEXT) ! 198: distpte(&text[c->c_ndx], (int)c->c_page, rpte); ! 199: } ! 200: switch (type) { ! 201: ! 202: case CSYS: ! 203: c->c_ndx = px; ! 204: break; ! 205: ! 206: case CTEXT: ! 207: c->c_page = vtotp(p, ptetov(p, pte)); ! 208: c->c_ndx = p->p_textp - &text[0]; ! 209: break; ! 210: ! 211: case CDATA: ! 212: c->c_page = vtodp(p, ptetov(p, pte)); ! 213: c->c_ndx = px; ! 214: break; ! 215: ! 216: case CSTACK: ! 217: c->c_page = vtosp(p, ptetov(p, pte)); ! 218: c->c_ndx = px; ! 219: break; ! 220: } ! 221: if (c->c_blkno) { ! 222: /* ! 223: * This is very like munhash(), except ! 224: * that we really don't want to bother ! 225: * to calculate a dev to pass to it. ! 226: */ ! 227: j = CMHASH(c->c_blkno); ! 228: c1 = &cmap[cmhash[j]]; ! 229: if (c1 == c) ! 230: cmhash[j] = c1->c_hlink; ! 231: else { ! 232: for (;;) { ! 233: if (c1 == ecmap) ! 234: panic("memall ecmap"); ! 235: c2 = c1; ! 236: c1 = &cmap[c2->c_hlink]; ! 237: if (c1 == c) ! 238: break; ! 239: } ! 240: c2->c_hlink = c1->c_hlink; ! 241: } ! 242: if (mfind(c->c_mdev, (daddr_t)c->c_blkno)) ! 243: panic("memall mfind"); ! 244: c1->c_mdev = 0; ! 245: c1->c_blkno = 0; ! 246: c1->c_hlink = 0; ! 247: } ! 248: pf = cmtopg(c - cmap); ! 249: for (j = 0; j < CLSIZE; j++) ! 250: *(int *)pte++ = pf++; ! 251: c->c_free = 0; ! 252: c->c_gone = 0; ! 253: if (c->c_intrans || c->c_want) ! 254: panic("memall intrans|want"); ! 255: c->c_lock = 1; ! 256: c->c_type = type; ! 257: freemem -= CLSIZE; ! 258: j = c->c_next; ! 259: cmap[CMHEAD].c_next = j; ! 260: cmap[j].c_prev = CMHEAD; ! 261: } ! 262: return (size); ! 263: } ! 264: ! 265: /* ! 266: * Free memory - ! 267: * ! 268: * The page frames being returned are inserted ! 269: * to the head/tail of the free list depending ! 270: * on whether there is any possible future use of them. ! 271: * ! 272: * If the freemem count had been zero, ! 273: * the processes sleeping for memory ! 274: * are awakened. ! 275: */ ! 276: memfree(pte, size, detach) ! 277: register struct pte *pte; ! 278: register int size; ! 279: { ! 280: register int i, j, prev, next; ! 281: register struct cmap *c; ! 282: ! 283: if (size % CLSIZE) ! 284: panic("memfree"); ! 285: if (freemem < CLSIZE * KLMAX) ! 286: wakeup((caddr_t)&freemem); ! 287: while (size > 0) { ! 288: size -= CLSIZE; ! 289: i = pte->pg_pfnum; ! 290: if (i < firstfree || i > maxfree) ! 291: panic("bad mem free"); ! 292: i = pgtocm(i); ! 293: c = &cmap[i]; ! 294: if (c->c_free) ! 295: panic("dup mem free"); ! 296: if (detach && c->c_type != CSYS) { ! 297: for (j = 0; j < CLSIZE; j++) ! 298: *(int *)(pte+j) &= (PG_PROT|PG_VREADM); ! 299: c->c_gone = 1; ! 300: } ! 301: if (detach && c->c_blkno == 0) { ! 302: next = cmap[CMHEAD].c_next; ! 303: cmap[next].c_prev = i; ! 304: c->c_prev = CMHEAD; ! 305: c->c_next = next; ! 306: cmap[CMHEAD].c_next = i; ! 307: } else { ! 308: prev = cmap[CMHEAD].c_prev; ! 309: cmap[prev].c_next = i; ! 310: c->c_next = CMHEAD; ! 311: c->c_prev = prev; ! 312: cmap[CMHEAD].c_prev = i; ! 313: } ! 314: c->c_free = 1; ! 315: freemem += CLSIZE; ! 316: pte += CLSIZE; ! 317: } ! 318: } ! 319: ! 320: /* ! 321: * Enter cmap block c on the hash chains. ! 322: * It contains file system block bn from device dev. ! 323: * Dev must either be a mounted file system or the swap device ! 324: * so we panic if getfsx() cannot find it. ! 325: */ ! 326: mhash(c, mdev, bn) ! 327: register struct cmap *c; ! 328: int mdev; ! 329: daddr_t bn; ! 330: { ! 331: register int i = CMHASH(bn); ! 332: ! 333: if (mdev == -1) ! 334: panic("mhash"); ! 335: c->c_hlink = cmhash[i]; ! 336: cmhash[i] = c - cmap; ! 337: c->c_blkno = bn; ! 338: c->c_mdev = mdev; ! 339: } ! 340: ! 341: /* ! 342: * Pull the clist entry of <dev,bn> off the hash chains. ! 343: * We have checked before calling (using mfind) that the ! 344: * entry really needs to be unhashed, so panic if we can't ! 345: * find it (can't happen). ! 346: */ ! 347: munhash(mdev, bn) ! 348: register int mdev; ! 349: daddr_t bn; ! 350: { ! 351: register int i = CMHASH(bn); ! 352: register struct cmap *c1, *c2; ! 353: ! 354: c1 = &cmap[cmhash[i]]; ! 355: if (c1 == ecmap) ! 356: panic("munhash"); ! 357: if (c1->c_blkno == bn && mdev == c1->c_mdev) ! 358: cmhash[i] = c1->c_hlink; ! 359: else { ! 360: for (;;) { ! 361: c2 = c1; ! 362: c1 = &cmap[c2->c_hlink]; ! 363: if (c1 == ecmap) ! 364: panic("munhash"); ! 365: if (c1->c_blkno == bn && mdev == c1->c_mdev) ! 366: break; ! 367: } ! 368: c2->c_hlink = c1->c_hlink; ! 369: } ! 370: if (mfind(mdev, bn)) ! 371: panic("munhash mfind"); ! 372: c1->c_mdev = 0; ! 373: c1->c_blkno = 0; ! 374: c1->c_hlink = 0; ! 375: } ! 376: ! 377: /* ! 378: * Look for block bn of device dev in the free pool. ! 379: * Currently it should not be possible to find it unless it is ! 380: * c_free and c_gone, although this may later not be true. ! 381: * (This is because active texts are locked against file system ! 382: * writes by the system.) ! 383: */ ! 384: struct cmap * ! 385: mfind(mdev, bn) ! 386: register int mdev; ! 387: daddr_t bn; ! 388: { ! 389: register struct cmap *c1 = &cmap[cmhash[CMHASH(bn)]]; ! 390: ! 391: while (c1 != ecmap) { ! 392: if (c1->c_blkno == bn && c1->c_mdev == mdev) ! 393: return (c1); ! 394: c1 = &cmap[c1->c_hlink]; ! 395: } ! 396: return ((struct cmap *)0); ! 397: } ! 398: ! 399: /* ! 400: * Purge blocks from device dev from incore cache ! 401: * before umount(). ! 402: */ ! 403: mpurge(mdev) ! 404: int mdev; ! 405: { ! 406: register struct cmap *c1, *c2; ! 407: register int i; ! 408: ! 409: for (i = 0; i < CMHSIZ; i++) { ! 410: more: ! 411: c1 = &cmap[cmhash[i]]; ! 412: if (c1 == ecmap) ! 413: continue; ! 414: if (c1->c_mdev == mdev) ! 415: cmhash[i] = c1->c_hlink; ! 416: else { ! 417: for (;;) { ! 418: c2 = c1; ! 419: c1 = &cmap[c1->c_hlink]; ! 420: if (c1 == ecmap) ! 421: goto cont; ! 422: if (c1->c_mdev == mdev) ! 423: break; ! 424: } ! 425: c2->c_hlink = c1->c_hlink; ! 426: } ! 427: c1->c_mdev = 0; ! 428: c1->c_blkno = 0; ! 429: c1->c_hlink = 0; ! 430: goto more; ! 431: cont: ! 432: ; ! 433: } ! 434: } ! 435: ! 436: /* ! 437: * Initialize core map ! 438: */ ! 439: meminit(first, last) ! 440: int first, last; ! 441: { ! 442: register int i; ! 443: register struct cmap *c; ! 444: ! 445: firstfree = clrnd(first); ! 446: maxfree = clrnd(last - (CLSIZE - 1)); ! 447: freemem = maxfree - firstfree; ! 448: ecmx = ecmap - cmap; ! 449: if (ecmx < freemem / CLSIZE) ! 450: freemem = ecmx * CLSIZE; ! 451: for (i = 1; i <= freemem / CLSIZE; i++) { ! 452: cmap[i-1].c_next = i; ! 453: c = &cmap[i]; ! 454: c->c_prev = i-1; ! 455: c->c_free = 1; ! 456: c->c_gone = 1; ! 457: c->c_type = CSYS; ! 458: c->c_mdev = 0; ! 459: c->c_blkno = 0; ! 460: } ! 461: cmap[freemem / CLSIZE].c_next = CMHEAD; ! 462: for (i = 0; i < CMHSIZ; i++) ! 463: cmhash[i] = ecmx; ! 464: cmap[CMHEAD].c_prev = freemem / CLSIZE; ! 465: cmap[CMHEAD].c_type = CSYS; ! 466: avefree = freemem; ! 467: } ! 468: ! 469: /* ! 470: * Wait for frame pf to become unlocked ! 471: * if it is currently locked. ! 472: * ! 473: * THIS ROUTINE SHOULD TAKE A CMAP STRUCTURE AS ARGUMENT. ! 474: */ ! 475: mwait(pf) ! 476: unsigned pf; ! 477: { ! 478: ! 479: mlock(pf); ! 480: munlock(pf); ! 481: } ! 482: ! 483: /* ! 484: * Lock a page frame. ! 485: * ! 486: * THIS ROUTINE SHOULD TAKE A CMAP STRUCTURE AS ARGUMENT. ! 487: */ ! 488: mlock(pf) ! 489: unsigned pf; ! 490: { ! 491: register struct cmap *c = &cmap[pgtocm(pf)]; ! 492: ! 493: while (c->c_lock) { ! 494: c->c_want = 1; ! 495: sleep((caddr_t)c, PSWP+1); ! 496: } ! 497: c->c_lock = 1; ! 498: } ! 499: ! 500: /* ! 501: * Unlock a page frame. ! 502: * ! 503: * THIS ROUTINE SHOULD TAKE A CMAP STRUCTURE AS ARGUMENT. ! 504: */ ! 505: munlock(pf) ! 506: unsigned pf; ! 507: { ! 508: register struct cmap *c = &cmap[pgtocm(pf)]; ! 509: ! 510: if (c->c_lock == 0) ! 511: panic("dup page unlock"); ! 512: if (c->c_want) ! 513: wakeup((caddr_t)c); ! 514: c->c_lock = 0; ! 515: c->c_want = 0; ! 516: } ! 517: ! 518: /* ! 519: * Lock a virtual segment. ! 520: * ! 521: * For each cluster of pages, if the cluster is not valid, ! 522: * touch it to fault it in, otherwise just lock page frame. ! 523: * Called from physio to ensure that the pages ! 524: * participating in raw i/o are valid and locked. ! 525: * We use SDLYU to keep pagein from unlocking pages, ! 526: * so they make it safely back here locked. ! 527: */ ! 528: vslock(base, count) ! 529: caddr_t base; ! 530: { ! 531: register unsigned v; ! 532: register int npf; ! 533: register struct pte *pte; ! 534: ! 535: u.u_procp->p_flag |= SDLYU; ! 536: v = btop(base); ! 537: pte = vtopte(u.u_procp, v); ! 538: npf = btoc(count + ((int)base & CLOFSET)); ! 539: while (npf > 0) { ! 540: if (pte->pg_v) ! 541: mlock(pte->pg_pfnum); ! 542: else ! 543: if (fubyte((caddr_t)ctob(v)) < 0) ! 544: panic("vslock"); ! 545: pte += CLSIZE; ! 546: v += CLSIZE; ! 547: npf -= CLSIZE; ! 548: } ! 549: u.u_procp->p_flag &= ~SDLYU; ! 550: } ! 551: ! 552: /* ! 553: * Unlock a virtual segment. ! 554: */ ! 555: vsunlock(base, count, rw) ! 556: caddr_t base; ! 557: { ! 558: register struct pte *pte; ! 559: register int npf; ! 560: ! 561: pte = vtopte(u.u_procp, btop(base)); ! 562: npf = btoc(count + ((int)base & CLOFSET)); ! 563: while (npf > 0) { ! 564: munlock(pte->pg_pfnum); ! 565: if (rw == B_READ) /* Reading from device writes memory */ ! 566: pte->pg_m = 1; ! 567: pte += CLSIZE; ! 568: npf -= CLSIZE; ! 569: } ! 570: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.