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