|
|
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.