1: /* 2: * Copyright (c) 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)vm_text.c 1.2 (2.11BSD GTE) 11/26/94 7: */ 8: 9: #include "param.h" 10: #include "../machine/seg.h" 11: 12: #include "map.h" 13: #include "user.h" 14: #include "proc.h" 15: #include "text.h" 16: #include "inode.h" 17: #include "buf.h" 18: #include "uio.h" 19: #include "systm.h" 20: 21: #define X_LOCK(xp) { \ 22: while ((xp)->x_flag & XLOCK) { \ 23: (xp)->x_flag |= XWANT; \ 24: sleep((caddr_t)(xp), PSWP); \ 25: } \ 26: (xp)->x_flag |= XLOCK; \ 27: } 28: #define XUNLOCK(xp) { \ 29: if ((xp)->x_flag & XWANT) \ 30: wakeup((caddr_t)(xp)); \ 31: (xp)->x_flag &= ~(XLOCK|XWANT); \ 32: } 33: #define FREE_AT_HEAD(xp) { \ 34: (xp)->x_forw = xhead; \ 35: xhead = (xp); \ 36: (xp)->x_back = &xhead; \ 37: if (xtail == &xhead) \ 38: xtail = &(xp)->x_forw; \ 39: else \ 40: (xp)->x_forw->x_back = &(xp)->x_forw; \ 41: } 42: #define FREE_AT_TAIL(xp) { \ 43: (xp)->x_back = xtail; \ 44: *xtail = (xp); \ 45: xtail = &(xp)->x_forw; \ 46: /* x_forw is NULL */ \ 47: } 48: #define ALLOC(xp) { \ 49: *((xp)->x_back) = (xp)->x_forw; \ 50: if ((xp)->x_forw) \ 51: (xp)->x_forw->x_back = (xp)->x_back; \ 52: else \ 53: xtail = (xp)->x_back; \ 54: (xp)->x_forw = NULL; \ 55: (xp)->x_back = NULL; \ 56: } 57: 58: /* 59: * We place free text table entries on a free list. 60: * All text images are treated as "sticky," 61: * and are placed on the free list (as an LRU cache) when unused. 62: * They may be reclaimed from the free list until reused. 63: * Files marked sticky are locked into the table, and are never freed. 64: */ 65: struct text *xhead, **xtail; /* text table free list */ 66: #ifdef UCB_METER 67: struct xstats xstats; /* cache statistics */ 68: #endif 69: 70: /* 71: * initialize text table 72: */ 73: xinit() 74: { 75: register struct text *xp; 76: 77: xtail = &xhead; 78: for (xp = text; xp < textNTEXT; xp++) 79: FREE_AT_TAIL(xp); 80: } 81: 82: /* 83: * Decrement loaded reference count of text object. If not sticky and 84: * count of zero, attach to LRU cache, at the head if traced or the 85: * inode has a hard link count of zero, otherwise at the tail. 86: */ 87: xfree() 88: { 89: register struct text *xp; 90: 91: if ((xp = u.u_procp->p_textp) == NULL) 92: return; 93: #ifdef UCB_METER 94: xstats.free++; 95: #endif 96: X_LOCK(xp); 97: /* 98: * Don't add the following test to the "if" below: 99: * 100: * (xp->x_iptr->i_mode & ISVTX) == 0 101: * 102: * all text under 2.10 is sticky in an LRU cache. Putting the 103: * above test in makes sticky text objects ``gluey'' and nearly 104: * impossible to flush from memory. 105: */ 106: if (--xp->x_count == 0) { 107: if (xp->x_flag & XTRC || xp->x_iptr->i_nlink == 0) { 108: xp->x_flag &= ~XLOCK; 109: xuntext(xp); 110: FREE_AT_HEAD(xp); 111: } else { 112: #ifdef UCB_METER 113: if (xp->x_flag & XWRIT) { 114: xstats.free_cacheswap++; 115: xp->x_flag |= XUNUSED; 116: } 117: xstats.free_cache++; 118: #endif 119: --xp->x_ccount; 120: FREE_AT_TAIL(xp); 121: } 122: } else { 123: --xp->x_ccount; 124: #ifdef UCB_METER 125: xstats.free_inuse++; 126: #endif 127: } 128: XUNLOCK(xp); 129: u.u_procp->p_textp = NULL; 130: } 131: 132: /* 133: * Attach to a shared text segment. If there is no shared text, just 134: * return. If there is, hook up to it. If it is not available from 135: * core or swap, it has to be read in from the inode (ip); the written 136: * bit is set to force it to be written out as appropriate. If it is 137: * not available from core, a swap has to be done to get it back. 138: */ 139: xalloc(ip, ep) 140: struct exec *ep; 141: register struct inode *ip; 142: { 143: register struct text *xp; 144: register u_int count; 145: off_t offset; 146: size_t ts; 147: 148: if (ep->a_text == 0) 149: return; 150: #ifdef UCB_METER 151: xstats.alloc++; 152: #endif 153: while ((xp = ip->i_text) != NULL) { 154: if (xp->x_flag&XLOCK) { 155: /* 156: * Wait for text to be unlocked, 157: * then start over (may have changed state). 158: */ 159: xwait(xp); 160: continue; 161: } 162: X_LOCK(xp); 163: if (xp->x_back) { 164: ALLOC(xp); 165: #ifdef UCB_METER 166: xstats.alloc_cachehit++; 167: xp->x_flag &= ~XUNUSED; 168: #endif 169: } 170: #ifdef UCB_METER 171: else 172: xstats.alloc_inuse++; 173: #endif 174: xp->x_count++; 175: u.u_procp->p_textp = xp; 176: if (!xp->x_caddr && !xp->x_ccount) 177: xexpand(xp); 178: else 179: ++xp->x_ccount; 180: XUNLOCK(xp); 181: return; 182: } 183: xp = xhead; 184: if (xp == NULL) { 185: tablefull("text"); 186: psignal(u.u_procp, SIGKILL); 187: return; 188: } 189: ALLOC(xp); 190: if (xp->x_iptr) { 191: #ifdef UCB_METER 192: xstats.alloc_cacheflush++; 193: if (xp->x_flag & XUNUSED) 194: xstats.alloc_unused++; 195: #endif 196: xuntext(xp); 197: } 198: xp->x_flag = XLOAD|XLOCK; 199: ts = btoc(ep->a_text); 200: if (u.u_ovdata.uo_ovbase) 201: xp->x_size = u.u_ovdata.uo_ov_offst[NOVL]; 202: else 203: xp->x_size = ts; 204: if ((xp->x_daddr = malloc(swapmap, (size_t)ctod(xp->x_size))) == NULL) { 205: swkill(u.u_procp, "xalloc"); 206: return; 207: } 208: xp->x_count = 1; 209: xp->x_ccount = 0; 210: xp->x_iptr = ip; 211: ip->i_flag |= ITEXT; 212: ip->i_text = xp; 213: ip->i_count++; 214: u.u_procp->p_textp = xp; 215: xexpand(xp); 216: estabur(ts, (u_int)0, (u_int)0, 0, RW); 217: offset = sizeof(struct exec); 218: if (u.u_ovdata.uo_ovbase) 219: offset += (NOVL + 1) * sizeof(u_int); 220: u.u_procp->p_flag |= SLOCK; 221: u.u_error = rdwri(UIO_READ, ip, (caddr_t)0, ep->a_text & ~1, 222: offset, UIO_USERISPACE, IO_UNIT, (int *)0); 223: 224: if (u.u_ovdata.uo_ovbase) { /* read in overlays if necessary */ 225: register int i; 226: 227: offset += (off_t)(ep->a_text & ~1); 228: for (i = 1; i <= NOVL; i++) { 229: u.u_ovdata.uo_curov = i; 230: count = ctob(u.u_ovdata.uo_ov_offst[i] - u.u_ovdata.uo_ov_offst[i-1]); 231: if (count) { 232: choverlay(RW); 233: u.u_error = rdwri(UIO_READ, ip, 234: (caddr_t)(ctob(stoc(u.u_ovdata.uo_ovbase))), 235: count, offset, UIO_USERISPACE, 236: IO_UNIT, (int *)0); 237: offset += (off_t) count; 238: } 239: } 240: } 241: u.u_ovdata.uo_curov = 0; 242: u.u_procp->p_flag &= ~SLOCK; 243: xp->x_flag |= XWRIT; 244: xp->x_flag &= ~XLOAD; 245: } 246: 247: /* 248: * Assure core for text segment. If there isn't enough room to get process 249: * in core, swap self out. x_ccount must be 0. Text must be locked to keep 250: * someone else from freeing it in the meantime. Don't change the locking, 251: * it's correct. 252: */ 253: xexpand(xp) 254: register struct text *xp; 255: { 256: if ((xp->x_caddr = malloc(coremap, xp->x_size)) != NULL) { 257: if ((xp->x_flag & XLOAD) == 0) 258: swap(xp->x_daddr, xp->x_caddr, xp->x_size, B_READ); 259: xp->x_ccount++; 260: XUNLOCK(xp); 261: return; 262: } 263: if (setjmp(&u.u_ssave)) { 264: sureg(); 265: return; 266: } 267: swapout(u.u_procp, X_FREECORE, X_OLDSIZE, X_OLDSIZE); 268: XUNLOCK(xp); 269: u.u_procp->p_flag |= SSWAP; 270: swtch(); 271: /* NOTREACHED */ 272: } 273: 274: /* 275: * Lock and unlock a text segment from swapping 276: */ 277: xlock(xp) 278: register struct text *xp; 279: { 280: 281: X_LOCK(xp); 282: } 283: 284: /* 285: * Wait for xp to be unlocked if it is currently locked. 286: */ 287: xwait(xp) 288: register struct text *xp; 289: { 290: 291: X_LOCK(xp); 292: XUNLOCK(xp); 293: } 294: 295: xunlock(xp) 296: register struct text *xp; 297: { 298: 299: XUNLOCK(xp); 300: } 301: 302: /* 303: * Decrement the in-core usage count of a shared text segment. 304: * When it drops to zero, free the core space. Write the swap 305: * copy of the text if as yet unwritten. 306: */ 307: xccdec(xp) 308: register struct text *xp; 309: { 310: if (!xp->x_ccount) 311: return; 312: X_LOCK(xp); 313: if (--xp->x_ccount == 0) { 314: if (xp->x_flag & XWRIT) { 315: swap(xp->x_daddr, xp->x_caddr, xp->x_size, B_WRITE); 316: xp->x_flag &= ~XWRIT; 317: } 318: mfree(coremap, xp->x_size, xp->x_caddr); 319: xp->x_caddr = NULL; 320: } 321: XUNLOCK(xp); 322: } 323: 324: /* 325: * Free the swap image of all unused saved-text text segments which are from 326: * device dev (used by umount system call). If dev is NODEV, do all devices 327: * (used when rebooting or malloc of swapmap failed). 328: */ 329: xumount(dev) 330: register dev_t dev; 331: { 332: register struct text *xp; 333: 334: for (xp = text; xp < textNTEXT; xp++) 335: if (xp->x_iptr != NULL && 336: (dev == xp->x_iptr->i_dev || dev == NODEV)) 337: xuntext(xp); 338: } 339: 340: /* 341: * Remove text image from the text table. 342: * the use count must be zero. 343: */ 344: xuntext(xp) 345: register struct text *xp; 346: { 347: register struct inode *ip; 348: 349: X_LOCK(xp); 350: if (xp->x_count == 0) { 351: ip = xp->x_iptr; 352: xp->x_iptr = NULL; 353: mfree(swapmap, ctod(xp->x_size), xp->x_daddr); 354: if (xp->x_caddr) 355: mfree(coremap, xp->x_size, xp->x_caddr); 356: ip->i_flag &= ~ITEXT; 357: ip->i_text = NULL; 358: irele(ip); 359: } 360: XUNLOCK(xp); 361: } 362: 363: /* 364: * Free up "size" core; if swap copy of text has not yet been written, 365: * do so. 366: */ 367: xuncore(size) 368: register size_t size; 369: { 370: register struct text *xp; 371: 372: for (xp = xhead; xp; xp = xp->x_forw) { 373: if (!xp->x_iptr) 374: continue; 375: X_LOCK(xp); 376: if (!xp->x_ccount && xp->x_caddr) { 377: if (xp->x_flag & XWRIT) { 378: swap(xp->x_daddr, xp->x_caddr, xp->x_size, B_WRITE); 379: xp->x_flag &= ~XWRIT; 380: } 381: mfree(coremap, xp->x_size, xp->x_caddr); 382: xp->x_caddr = NULL; 383: if (xp->x_size >= size) { 384: XUNLOCK(xp); 385: return; 386: } 387: } 388: XUNLOCK(xp); 389: } 390: }