|
|
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_text.c 7.9 (Berkeley) 6/28/90 ! 21: */ ! 22: ! 23: #include "param.h" ! 24: #include "systm.h" ! 25: #include "user.h" ! 26: #include "proc.h" ! 27: #include "text.h" ! 28: #include "vnode.h" ! 29: #include "buf.h" ! 30: #include "seg.h" ! 31: #include "cmap.h" ! 32: #include "uio.h" ! 33: #include "exec.h" ! 34: #include "vm.h" ! 35: ! 36: #include "machine/pte.h" ! 37: #include "machine/cpu.h" ! 38: ! 39: #define X_LOCK(xp) { \ ! 40: while ((xp)->x_flag & XLOCK) { \ ! 41: (xp)->x_flag |= XWANT; \ ! 42: sleep((caddr_t)(xp), PSWP); \ ! 43: } \ ! 44: (xp)->x_flag |= XLOCK; \ ! 45: } ! 46: #define XUNLOCK(xp) { \ ! 47: if ((xp)->x_flag & XWANT) \ ! 48: wakeup((caddr_t)(xp)); \ ! 49: (xp)->x_flag &= ~(XLOCK|XWANT); \ ! 50: } ! 51: #define FREE_AT_HEAD(xp) { \ ! 52: (xp)->x_forw = xhead; \ ! 53: xhead = (xp); \ ! 54: (xp)->x_back = &xhead; \ ! 55: if (xtail == &xhead) \ ! 56: xtail = &(xp)->x_forw; \ ! 57: else \ ! 58: (xp)->x_forw->x_back = &(xp)->x_forw; \ ! 59: } ! 60: #define FREE_AT_TAIL(xp) { \ ! 61: (xp)->x_back = xtail; \ ! 62: *xtail = (xp); \ ! 63: xtail = &(xp)->x_forw; \ ! 64: /* x_forw is NULL */ \ ! 65: } ! 66: #define ALLOC(xp) { \ ! 67: *((xp)->x_back) = (xp)->x_forw; \ ! 68: if ((xp)->x_forw) \ ! 69: (xp)->x_forw->x_back = (xp)->x_back; \ ! 70: else \ ! 71: xtail = (xp)->x_back; \ ! 72: (xp)->x_forw = NULL; \ ! 73: (xp)->x_back = NULL; \ ! 74: } ! 75: ! 76: /* ! 77: * The text-cache: ! 78: * ! 79: * We place up to ``maxtextcache'' free text table entries on a free list ! 80: * to form an LRU cache. This causes the swap (but not RAM) resources to ! 81: * be saved. These text images are treated as "sticky", and are placed on ! 82: * the free list when unused. They may be reclaimed from the free list ! 83: * until reused. The cache changes to MRU once the maximum limit is ! 84: * reached since we just cease caching new texts rather than replacing ! 85: * the LRU one (should be fixed). All cached text resources may be ! 86: * reclaimed by calling xpurge(). Currently, swpexpand() and xalloc() do ! 87: * this if an attempted swap allocation fails. ! 88: * ! 89: * Note that although true "sticky" texts are handling in the same way, ! 90: * they are not considered part of the cache; i.e. they are not subject ! 91: * to the maximum limit nor are they purged with xpurge(). They are in ! 92: * a sense "locked down" cache entries. ! 93: */ ! 94: struct text *xhead, **xtail; /* text table free list */ ! 95: int xcache; /* number of "sticky" texts retained */ ! 96: int maxtextcache = -1; /* maximum number of "sticky" texts */ ! 97: struct xstats xstats; /* cache statistics */ ! 98: ! 99: /* ! 100: * initialize text table ! 101: */ ! 102: xinit() ! 103: { ! 104: register struct text *xp; ! 105: ! 106: xtail = &xhead; ! 107: for (xp = text; xp < textNTEXT; xp++) ! 108: FREE_AT_TAIL(xp); ! 109: if (maxtextcache == -1) ! 110: maxtextcache = ntext; ! 111: } ! 112: ! 113: /* ! 114: * relinquish use of the shared text segment ! 115: * of a process. ! 116: */ ! 117: xfree() ! 118: { ! 119: register struct text *xp; ! 120: register struct vnode *vp; ! 121: struct vattr vattr; ! 122: ! 123: if ((xp = u.u_procp->p_textp) == NULL) ! 124: return; ! 125: xstats.free++; ! 126: X_LOCK(xp); ! 127: vp = xp->x_vptr; ! 128: if (--xp->x_count == 0 && ! 129: (VOP_GETATTR(vp, &vattr, u.u_cred) != 0 || ! 130: (vattr.va_mode & VSVTX) == 0)) { ! 131: if (xcache >= maxtextcache || xp->x_flag & XTRC || ! 132: vattr.va_nlink == 0) { /* XXX */ ! 133: xp->x_rssize -= vmemfree(tptopte(u.u_procp, 0), ! 134: (int)u.u_tsize); ! 135: if (xp->x_rssize != 0) ! 136: panic("xfree rssize"); ! 137: while (xp->x_poip) ! 138: sleep((caddr_t)&xp->x_poip, PSWP+1); ! 139: xp->x_flag &= ~XLOCK; ! 140: xuntext(xp); ! 141: FREE_AT_HEAD(xp); ! 142: } else { ! 143: if (xp->x_flag & XWRIT) { ! 144: xstats.free_cacheswap++; ! 145: xp->x_flag |= XUNUSED; ! 146: } ! 147: xcache++; ! 148: xstats.free_cache++; ! 149: xp->x_flag |= XCACHED; ! 150: xccdec(xp, u.u_procp); ! 151: #if defined(tahoe) ! 152: xp->x_ckey = 0; ! 153: #endif ! 154: FREE_AT_TAIL(xp); ! 155: } ! 156: } else { ! 157: #if defined(tahoe) ! 158: if (xp->x_count == 0) ! 159: xp->x_ckey = 0; ! 160: #endif ! 161: xccdec(xp, u.u_procp); ! 162: xstats.free_inuse++; ! 163: } ! 164: xunlink(u.u_procp); ! 165: XUNLOCK(xp); ! 166: u.u_procp->p_textp = NULL; ! 167: } ! 168: ! 169: /* ! 170: * Attach to a shared text segment. ! 171: * If there is no shared text, just return. ! 172: * If there is, hook up to it: ! 173: * if it is not currently being used, it has to be read ! 174: * in from the vnode (vp); the written bit is set to force it ! 175: * to be written out as appropriate. ! 176: * If it is being used, but is not currently in core, ! 177: * a swap has to be done to get it back. ! 178: */ ! 179: xalloc(vp, ep, toff, cred) ! 180: register struct vnode *vp; ! 181: struct exec *ep; ! 182: off_t toff; ! 183: struct ucred *cred; ! 184: { ! 185: register struct text *xp; ! 186: register struct proc *p; ! 187: ! 188: if (ep->a_text == 0) ! 189: return; ! 190: xstats.alloc++; ! 191: p = u.u_procp; ! 192: while ((xp = vp->v_text) != NULL) { ! 193: if (xp->x_flag&XLOCK) { ! 194: /* ! 195: * Wait for text to be unlocked, ! 196: * then start over (may have changed state). ! 197: */ ! 198: xwait(xp); ! 199: continue; ! 200: } ! 201: X_LOCK(xp); ! 202: if (xp->x_flag & XCACHED) { ! 203: xstats.alloc_cachehit++; ! 204: ALLOC(xp); ! 205: xp->x_flag &= ~(XCACHED|XUNUSED); ! 206: xcache--; ! 207: } else ! 208: xstats.alloc_inuse++; ! 209: xp->x_count++; ! 210: p->p_textp = xp; ! 211: xlink(p); ! 212: XUNLOCK(xp); ! 213: #if defined(tahoe) ! 214: ckeyrelease(p->p_ckey); ! 215: if (ckey_cnt[xp->x_ckey]) ! 216: ckey_cnt[xp->x_ckey]++; ! 217: else /* dead key */ ! 218: xp->x_ckey = getcodekey(); ! 219: p->p_ckey = xp->x_ckey; ! 220: #endif ! 221: return; ! 222: } ! 223: xp = xhead; ! 224: if (xp == NULL) { ! 225: tablefull("text"); ! 226: psignal(p, SIGKILL); ! 227: return; ! 228: } ! 229: ALLOC(xp); ! 230: if (xp->x_vptr) ! 231: xuntext(xp); ! 232: xp->x_flag = XLOAD|XLOCK; ! 233: if (p->p_flag & SPAGV) ! 234: xp->x_flag |= XPAGV; ! 235: xp->x_size = clrnd(btoc(ep->a_text)); ! 236: if (vsxalloc(xp) == NULL) { ! 237: /* flush text cache and try again */ ! 238: if (xpurge() == 0 || vsxalloc(xp) == NULL) { ! 239: swkill(p, "xalloc: no swap space"); ! 240: return; ! 241: } ! 242: } ! 243: xp->x_count = 1; ! 244: xp->x_ccount = 0; ! 245: xp->x_rssize = 0; ! 246: xp->x_mtime = 0; ! 247: xp->x_vptr = vp; ! 248: vp->v_flag |= VTEXT; ! 249: vp->v_text = xp; ! 250: VREF(vp); ! 251: p->p_textp = xp; ! 252: xlink(p); ! 253: if ((p->p_flag & SPAGV) == 0) { ! 254: settprot(RW); ! 255: p->p_flag |= SKEEP; ! 256: (void) vn_rdwr(UIO_READ, vp, ! 257: (caddr_t)ctob(tptov(p, 0)), ! 258: (int)ep->a_text, toff, ! 259: UIO_USERSPACE, (IO_UNIT|IO_NODELOCKED), cred, (int *)0); ! 260: p->p_flag &= ~SKEEP; ! 261: } ! 262: settprot(RO); ! 263: #if defined(tahoe) ! 264: ckeyrelease(p->p_ckey); ! 265: xp->x_ckey = getcodekey(); ! 266: p->p_ckey = xp->x_ckey; ! 267: #endif ! 268: xp->x_flag |= XWRIT; ! 269: xp->x_flag &= ~XLOAD; ! 270: XUNLOCK(xp); ! 271: } ! 272: ! 273: /* ! 274: * Lock and unlock a text segment from swapping ! 275: */ ! 276: xlock(xp) ! 277: register struct text *xp; ! 278: { ! 279: ! 280: X_LOCK(xp); ! 281: } ! 282: ! 283: /* ! 284: * Wait for xp to be unlocked if it is currently locked. ! 285: */ ! 286: xwait(xp) ! 287: register struct text *xp; ! 288: { ! 289: ! 290: X_LOCK(xp); ! 291: XUNLOCK(xp); ! 292: } ! 293: ! 294: xunlock(xp) ! 295: register struct text *xp; ! 296: { ! 297: ! 298: XUNLOCK(xp); ! 299: } ! 300: ! 301: /* ! 302: * Decrement the in-core usage count of a shared text segment, ! 303: * which must be locked. When the count drops to zero, ! 304: * free the core space. ! 305: */ ! 306: xccdec(xp, p) ! 307: register struct text *xp; ! 308: register struct proc *p; ! 309: { ! 310: ! 311: if (--xp->x_ccount == 0) { ! 312: if (xp->x_flag & XWRIT) { ! 313: vsswap(p, tptopte(p, 0), CTEXT, 0, (int)xp->x_size, ! 314: (struct dmap *)0); ! 315: if (xp->x_flag & XPAGV) ! 316: (void) swap(p, xp->x_ptdaddr, ! 317: (caddr_t)tptopte(p, 0), ! 318: (int)xp->x_size * sizeof (struct pte), ! 319: B_WRITE, B_PAGET, swapdev_vp, 0); ! 320: xp->x_flag &= ~XWRIT; ! 321: } else ! 322: xp->x_rssize -= vmemfree(tptopte(p, 0), ! 323: (int)xp->x_size); ! 324: if (xp->x_rssize != 0) ! 325: panic("text rssize"); ! 326: } ! 327: } ! 328: ! 329: /* ! 330: * Detach a process from the in-core text. ! 331: * External interface to xccdec, used when swapping out a process. ! 332: */ ! 333: xdetach(xp, p) ! 334: register struct text *xp; ! 335: struct proc *p; ! 336: { ! 337: ! 338: if (xp && xp->x_ccount != 0) { ! 339: X_LOCK(xp); ! 340: xccdec(xp, p); ! 341: xunlink(p); ! 342: XUNLOCK(xp); ! 343: } ! 344: } ! 345: ! 346: /* ! 347: * Free the swap image of all unused saved-text text segments ! 348: * which are from file system mp (used by umount system call). ! 349: */ ! 350: xumount(mp) ! 351: struct mount *mp; ! 352: { ! 353: register struct text *xp; ! 354: ! 355: for (xp = text; xp < textNTEXT; xp++) ! 356: if (xp->x_vptr != NULL && ! 357: (mp == NULL || (xp->x_vptr->v_mount == mp)) && ! 358: (xp->x_flag & XLOCK) == 0) ! 359: xuntext(xp); ! 360: mpurgemp(mp); ! 361: } ! 362: ! 363: /* ! 364: * Flush all cached text segments to reclaim swap space. ! 365: * Used during swap allocation when out of swap space. ! 366: */ ! 367: xpurge() ! 368: { ! 369: register struct text *xp; ! 370: int found = 0; ! 371: ! 372: xstats.purge++; ! 373: for (xp = text; xp < textNTEXT; xp++) ! 374: if (xp->x_vptr && (xp->x_flag & (XLOCK|XCACHED)) == XCACHED) { ! 375: xuntext(xp); ! 376: /* really gone? */ ! 377: if (xp->x_vptr == NULL) ! 378: found++; ! 379: } ! 380: return(found); ! 381: } ! 382: ! 383: /* ! 384: * remove a shared text segment from the text table, if possible. ! 385: */ ! 386: xrele(vp) ! 387: register struct vnode *vp; ! 388: { ! 389: ! 390: if (vp->v_flag & VTEXT) ! 391: xuntext(vp->v_text); ! 392: } ! 393: ! 394: /* ! 395: * remove text image from the text table. ! 396: * the use count must be zero. ! 397: */ ! 398: xuntext(xp) ! 399: register struct text *xp; ! 400: { ! 401: register struct vnode *vp; ! 402: ! 403: X_LOCK(xp); ! 404: if (xp->x_count == 0) { ! 405: vp = xp->x_vptr; ! 406: xp->x_vptr = NULL; ! 407: vsxfree(xp, (long)xp->x_size); ! 408: vp->v_flag &= ~VTEXT; ! 409: vp->v_text = NULL; ! 410: mpurge(vp); ! 411: vrele(vp); ! 412: /* ! 413: * Take care of text cache statistics ! 414: */ ! 415: if (xp->x_flag & XCACHED) { ! 416: if (xp->x_flag & XUNUSED) ! 417: xstats.alloc_unused++; ! 418: xp->x_flag &= ~(XCACHED|XUNUSED); ! 419: xstats.alloc_cacheflush++; ! 420: xcache--; ! 421: } ! 422: } ! 423: XUNLOCK(xp); ! 424: } ! 425: ! 426: /* ! 427: * Add a process to those sharing a text segment by ! 428: * getting the page tables and then linking to x_caddr. ! 429: */ ! 430: xlink(p) ! 431: register struct proc *p; ! 432: { ! 433: register struct text *xp = p->p_textp; ! 434: ! 435: if (xp == 0) ! 436: return; ! 437: vinitpt(p); ! 438: p->p_xlink = xp->x_caddr; ! 439: xp->x_caddr = p; ! 440: xp->x_ccount++; ! 441: } ! 442: ! 443: xunlink(p) ! 444: register struct proc *p; ! 445: { ! 446: register struct text *xp = p->p_textp; ! 447: register struct proc *q; ! 448: ! 449: if (xp == 0) ! 450: return; ! 451: if (xp->x_caddr == p) { ! 452: xp->x_caddr = p->p_xlink; ! 453: p->p_xlink = 0; ! 454: return; ! 455: } ! 456: for (q = xp->x_caddr; q->p_xlink; q = q->p_xlink) ! 457: if (q->p_xlink == p) { ! 458: q->p_xlink = p->p_xlink; ! 459: p->p_xlink = 0; ! 460: return; ! 461: } ! 462: panic("lost text"); ! 463: } ! 464: ! 465: /* ! 466: * Replace p by q in a text incore linked list. ! 467: * Used by vfork(), internally. ! 468: */ ! 469: xrepl(p, q) ! 470: struct proc *p, *q; ! 471: { ! 472: register struct text *xp = q->p_textp; ! 473: ! 474: if (xp == 0) ! 475: return; ! 476: xunlink(p); ! 477: q->p_xlink = xp->x_caddr; ! 478: xp->x_caddr = q; ! 479: } ! 480: ! 481: int xkillcnt = 0; ! 482: ! 483: /* ! 484: * Invalidate the text associated with vp. ! 485: * Purge in core cache of pages associated with vp and kill all active ! 486: * processes. ! 487: */ ! 488: xinval(vp) ! 489: struct vnode *vp; ! 490: { ! 491: register struct text *xp; ! 492: register struct proc *p; ! 493: int found = 0; ! 494: ! 495: mpurge(vp); ! 496: xp = vp->v_text; ! 497: if (xp->x_flag & XPAGV) { ! 498: for (p = xp->x_caddr; p; p = p->p_xlink) { ! 499: /* ! 500: * swkill without uprintf ! 501: */ ! 502: printf("pid %d killed due to text modification\n", ! 503: p->p_pid); ! 504: psignal(p, SIGKILL); ! 505: p->p_flag |= SULOCK; ! 506: xkillcnt++; ! 507: found++; ! 508: } ! 509: /* ! 510: * Take care of the text cache. ! 511: * If there was a process still using the text just mark ! 512: * the text as XTRC so it won't be cached. If no one was ! 513: * using it then it is in the cache and we need to flush ! 514: * it with xuntext. ! 515: */ ! 516: if (found) ! 517: xp->x_flag |= XTRC; ! 518: else ! 519: xuntext(xp); ! 520: } ! 521: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.