|
|
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_mem.c 7.15 (Berkeley) 6/28/90
21: */
22:
23: #include "param.h"
24: #include "systm.h"
25: #include "cmap.h"
26: #include "user.h"
27: #include "proc.h"
28: #include "text.h"
29: #include "vm.h"
30: #include "buf.h"
31: #include "vnode.h"
32: #include "mount.h"
33: #include "trace.h"
34:
35: #include "machine/pte.h"
36:
37: /*
38: * Allocate memory, and always succeed
39: * by jolting page-out daemon
40: * so as to obtain page frames.
41: * To be used in conjunction with vmemfree().
42: */
43: vmemall(pte, size, p, type)
44: register struct pte *pte;
45: int size;
46: struct proc *p;
47: {
48: register int m;
49:
50: if (size <= 0 || size > maxmem)
51: panic("vmemall size");
52: while (size > 0) {
53: if (freemem < desfree)
54: outofmem();
55: while (freemem == 0)
56: sleep((caddr_t)&freemem, PSWP+2);
57: m = imin(size, freemem);
58: (void) memall(pte, m, p, type);
59: size -= m;
60: pte += m;
61: }
62: if (freemem < desfree)
63: outofmem();
64: /*
65: * Always succeeds, but return success for
66: * vgetu and vgetpt (e.g.) which call either
67: * memall or vmemall depending on context.
68: */
69: return (1);
70: }
71:
72: /*
73: * Free valid and reclaimable page frames belonging to the
74: * count pages starting at pte. If a page is valid
75: * or reclaimable and locked (but not a system page), then
76: * we simply mark the page as c_gone and let the pageout
77: * daemon free the page when it is through with it.
78: * If a page is reclaimable, and already in the free list, then
79: * we mark the page as c_gone, and (of course) don't free it.
80: *
81: * Determines the largest contiguous cluster of
82: * valid pages and frees them in one call to memfree.
83: */
84: vmemfree(pte, count)
85: register struct pte *pte;
86: register int count;
87: {
88: register struct cmap *c;
89: register struct pte *spte;
90: register int j;
91: int size, pcnt;
92: #ifdef notdef
93: int fileno;
94: #endif
95:
96: if (count % CLSIZE)
97: panic("vmemfree");
98: for (size = 0, pcnt = 0; count > 0; pte += CLSIZE, count -= CLSIZE) {
99: if (pte->pg_fod == 0 && pte->pg_pfnum) {
100: c = &cmap[pgtocm(pte->pg_pfnum)];
101: pcnt += CLSIZE;
102: if (c->c_lock && c->c_type != CSYS) {
103: for (j = 0; j < CLSIZE; j++)
104: *(int *)(pte+j) &= PG_PROT;
105: c->c_gone = 1;
106: goto free;
107: }
108: if (c->c_free) {
109: pcnt -= CLSIZE;
110: for (j = 0; j < CLSIZE; j++)
111: *(int *)(pte+j) &= PG_PROT;
112: if (c->c_type == CTEXT)
113: distpte(&text[c->c_ndx], c->c_page,
114: pte);
115: c->c_gone = 1;
116: goto free;
117: }
118: if (size == 0)
119: spte = pte;
120: size += CLSIZE;
121: continue;
122: }
123: #ifdef notdef
124: /* Don't do anything with mapped ptes */
125: if (pte->pg_fod && pte->pg_v)
126: goto free;
127: #endif
128: if (pte->pg_fod) {
129: #ifdef notdef
130: fileno = ((struct fpte *)pte)->pg_fileno;
131: if (fileno < NOFILE)
132: panic("vmemfree vread");
133: #endif
134: for (j = 0; j < CLSIZE; j++)
135: *(int *)(pte+j) &= PG_PROT;
136: }
137: free:
138: if (size) {
139: memfree(spte, size, 1);
140: size = 0;
141: }
142: }
143: if (size)
144: memfree(spte, size, 1);
145: return (pcnt);
146: }
147:
148: /*
149: * Unlink a page frame from the free list -
150: *
151: * Performed if the page being reclaimed
152: * is in the free list.
153: */
154: munlink(c)
155: register struct cmap *c;
156: {
157: register int next, prev;
158:
159: next = c->c_next;
160: prev = c->c_prev;
161: cmap[prev].c_next = next;
162: cmap[next].c_prev = prev;
163: c->c_free = 0;
164: if (freemem < minfree)
165: outofmem();
166: freemem -= CLSIZE;
167: }
168:
169: /*
170: * Allocate memory -
171: *
172: * The free list appears as a doubly linked list
173: * in the core map with cmap[0] serving as a header.
174: */
175: memall(pte, size, p, type)
176: register struct pte *pte;
177: int size;
178: struct proc *p;
179: {
180: register struct cmap *c;
181: register struct pte *rpte;
182: register struct proc *rp;
183: int i, j, next, curpos;
184: unsigned pf;
185: struct cmap *c1, *c2;
186: int s;
187:
188: if (size % CLSIZE)
189: panic("memall");
190: s = splimp();
191: if (size > freemem) {
192: splx(s);
193: return (0);
194: }
195: trace(TR_MALL, size, u.u_procp->p_pid);
196: for (i = size; i > 0; i -= CLSIZE) {
197: curpos = cmap[CMHEAD].c_next;
198: c = &cmap[curpos];
199: freemem -= CLSIZE;
200: next = c->c_next;
201: cmap[CMHEAD].c_next = next;
202: cmap[next].c_prev = CMHEAD;
203: if (c->c_free == 0)
204: panic("dup mem alloc");
205: if (cmtopg(curpos) > maxfree)
206: panic("bad mem alloc");
207: if (c->c_gone == 0 && c->c_type != CSYS) {
208: if (c->c_type == CTEXT)
209: rp = text[c->c_ndx].x_caddr;
210: else
211: rp = &proc[c->c_ndx];
212: while (rp->p_flag & SNOVM)
213: rp = rp->p_xlink;
214: switch (c->c_type) {
215:
216: case CTEXT:
217: rpte = tptopte(rp, c->c_page);
218: break;
219:
220: case CDATA:
221: rpte = dptopte(rp, c->c_page);
222: break;
223:
224: case CSTACK:
225: rpte = sptopte(rp, c->c_page);
226: break;
227: }
228: zapcl(rpte, pg_pfnum) = 0;
229: if (c->c_type == CTEXT)
230: distpte(&text[c->c_ndx], c->c_page, rpte);
231: }
232: switch (type) {
233:
234: case CSYS:
235: c->c_ndx = p->p_ndx;
236: break;
237:
238: case CTEXT:
239: c->c_page = vtotp(p, ptetov(p, pte));
240: c->c_ndx = p->p_textp - &text[0];
241: break;
242:
243: case CDATA:
244: c->c_page = vtodp(p, ptetov(p, pte));
245: c->c_ndx = p->p_ndx;
246: break;
247:
248: case CSTACK:
249: c->c_page = vtosp(p, ptetov(p, pte));
250: c->c_ndx = p->p_ndx;
251: break;
252: }
253: if (c->c_blkno) {
254: /*
255: * This is very like munhash(), except
256: * that we really don't want to bother
257: * to calculate a vp to pass to it.
258: */
259: j = CMHASH(c->c_blkno);
260: c1 = &cmap[cmhash[j]];
261: if (c1 == c)
262: cmhash[j] = c1->c_hlink;
263: else {
264: for (;;) {
265: if (c1 == ecmap)
266: panic("memall ecmap");
267: c2 = c1;
268: c1 = &cmap[c2->c_hlink];
269: if (c1 == c)
270: break;
271: }
272: c2->c_hlink = c1->c_hlink;
273: }
274: if (mfind(c->c_vp, (daddr_t)(u_long)c->c_blkno))
275: panic("memall mfind");
276: HOLDRELE(c1->c_vp);
277: c1->c_vp = NULLVP;
278: c1->c_blkno = 0;
279: c1->c_hlink = 0;
280: }
281: pf = cmtopg(curpos);
282: for (j = 0; j < CLSIZE; j++) {
283: *(int *)pte = 0;
284: pte++->pg_pfnum = pf++;
285: }
286: c->c_free = 0;
287: c->c_gone = 0;
288: if (c->c_intrans || c->c_want)
289: panic("memall intrans|want");
290: c->c_lock = 1;
291: c->c_type = type;
292: }
293: splx(s);
294: return (size);
295: }
296:
297: /*
298: * Free memory -
299: *
300: * The page frames being returned are inserted
301: * to the head/tail of the free list depending
302: * on whether there is any possible future use of them.
303: *
304: * If the freemem count had been zero,
305: * the processes sleeping for memory
306: * are awakened.
307: */
308: memfree(pte, size, detach)
309: register struct pte *pte;
310: register int size;
311: {
312: register int i, j, prev, next;
313: register struct cmap *c;
314: int s;
315:
316: if (size % CLSIZE)
317: panic("memfree");
318: if (freemem < CLSIZE * KLMAX)
319: wakeup((caddr_t)&freemem);
320: while (size > 0) {
321: size -= CLSIZE;
322: i = pte->pg_pfnum;
323: if (i < firstfree || i > maxfree)
324: panic("bad mem free");
325: i = pgtocm(i);
326: c = &cmap[i];
327: if (c->c_free)
328: panic("dup mem free");
329: if (detach && c->c_type != CSYS) {
330: for (j = 0; j < CLSIZE; j++)
331: *(int *)(pte+j) &= PG_PROT;
332: c->c_gone = 1;
333: }
334: s = splimp();
335: if (detach && c->c_blkno == 0) {
336: next = cmap[CMHEAD].c_next;
337: cmap[next].c_prev = i;
338: c->c_prev = CMHEAD;
339: c->c_next = next;
340: cmap[CMHEAD].c_next = i;
341: } else {
342: prev = cmap[CMHEAD].c_prev;
343: cmap[prev].c_next = i;
344: c->c_next = CMHEAD;
345: c->c_prev = prev;
346: cmap[CMHEAD].c_prev = i;
347: }
348: c->c_free = 1;
349: freemem += CLSIZE;
350: splx(s);
351: pte += CLSIZE;
352: }
353: }
354:
355: /*
356: * Enter clist block c on the hash chains.
357: * It contains file system block bn from vnode vp.
358: */
359: mhash(c, vp, bn)
360: register struct cmap *c;
361: struct vnode *vp;
362: daddr_t bn;
363: {
364: register int i = CMHASH(bn);
365:
366: c->c_hlink = cmhash[i];
367: cmhash[i] = c - cmap;
368: c->c_blkno = bn;
369: c->c_vp = vp;
370: VHOLD(vp);
371: }
372:
373: /*
374: * Pull the clist entry of <vp,bn> off the hash chains
375: * if present.
376: */
377: munhash(vp, bn)
378: struct vnode *vp;
379: daddr_t bn;
380: {
381: int i = CMHASH(bn);
382: register struct cmap *c1, *c2;
383: int s = splimp();
384:
385: c1 = &cmap[cmhash[i]];
386: if (c1 == ecmap)
387: goto out;
388: if (c1->c_blkno == bn && c1->c_vp == vp)
389: cmhash[i] = c1->c_hlink;
390: else {
391: for (;;) {
392: c2 = c1;
393: c1 = &cmap[c2->c_hlink];
394: if (c1 == ecmap)
395: goto out;
396: if (c1->c_blkno == bn && c1->c_vp == vp)
397: break;
398: }
399: c2->c_hlink = c1->c_hlink;
400: }
401: HOLDRELE(vp);
402: c1->c_vp = NULLVP;
403: c1->c_blkno = 0;
404: c1->c_hlink = 0;
405: out:
406: splx(s);
407: }
408:
409: /*
410: * Look for block bn of vnode vp in the free pool.
411: * Currently it should not be possible to find it unless it is
412: * c_free and c_gone, although this may later not be true.
413: * (This is because active texts are locked against file system
414: * writes by the system.)
415: */
416: struct cmap *
417: mfind(vp, bn)
418: struct vnode *vp;
419: daddr_t bn;
420: {
421: register struct cmap *c1 = &cmap[cmhash[CMHASH(bn)]];
422: int si = splimp();
423:
424: while (c1 != ecmap) {
425: if (c1->c_blkno == bn && c1->c_vp == vp) {
426: splx(si);
427: return (c1);
428: }
429: c1 = &cmap[c1->c_hlink];
430: }
431: splx(si);
432: return ((struct cmap *)0);
433: }
434:
435: /*
436: * Purge blocks from vnode vp from incore cache
437: * before umount().
438: */
439: mpurge(vp)
440: struct vnode *vp;
441: {
442: register struct cmap *c1, *c2;
443: register int i;
444: int relcnt = 0, si = splimp();
445:
446: for (i = 0; i < CMHSIZ; i++) {
447: more:
448: c1 = &cmap[cmhash[i]];
449: if (c1 == ecmap)
450: continue;
451: if (c1->c_vp == vp)
452: cmhash[i] = c1->c_hlink;
453: else {
454: for (;;) {
455: c2 = c1;
456: c1 = &cmap[c1->c_hlink];
457: if (c1 == ecmap)
458: goto cont;
459: if (c1->c_vp == vp)
460: break;
461: }
462: c2->c_hlink = c1->c_hlink;
463: }
464: relcnt++;
465: c1->c_vp = NULLVP;
466: c1->c_blkno = 0;
467: c1->c_hlink = 0;
468: goto more;
469: cont:
470: ;
471: }
472: while (relcnt--)
473: HOLDRELE(vp);
474: splx(si);
475: }
476:
477: /*
478: * Purge blocks for filesystem mp from incore cache
479: * before umount().
480: */
481: mpurgemp(mp)
482: struct mount *mp;
483: {
484: register struct cmap *c1, *c2;
485: register int i;
486: int s = splimp();
487:
488: more:
489: for (i = 0; i < CMHSIZ; i++) {
490: c1 = &cmap[cmhash[i]];
491: if (c1 == ecmap)
492: continue;
493: if (mp == NULL || c1->c_vp->v_mount == mp)
494: cmhash[i] = c1->c_hlink;
495: else {
496: for (;;) {
497: c2 = c1;
498: c1 = &cmap[c1->c_hlink];
499: if (c1 == ecmap)
500: goto cont;
501: if (c1->c_vp->v_mount == mp)
502: break;
503: }
504: c2->c_hlink = c1->c_hlink;
505: }
506: (void) splx(s);
507: HOLDRELE(c1->c_vp);
508: s = splimp();
509: c1->c_vp = NULLVP;
510: c1->c_blkno = 0;
511: c1->c_hlink = 0;
512: goto more;
513: cont:
514: ;
515: }
516: (void) splx(s);
517: }
518:
519: /*
520: * Initialize core map
521: */
522: meminit(first, last)
523: int first, last;
524: {
525: register int i;
526: register struct cmap *c;
527:
528: firstfree = clrnd(first);
529: maxfree = clrnd(last - (CLSIZE - 1));
530: freemem = maxfree - firstfree;
531: ecmx = ecmap - cmap;
532: if (ecmx < freemem / CLSIZE)
533: freemem = ecmx * CLSIZE;
534: for (i = 1; i <= freemem / CLSIZE; i++) {
535: cmap[i-1].c_next = i;
536: c = &cmap[i];
537: c->c_prev = i-1;
538: c->c_free = 1;
539: c->c_gone = 1;
540: c->c_type = CSYS;
541: c->c_blkno = 0;
542: }
543: cmap[freemem / CLSIZE].c_next = CMHEAD;
544: for (i = 0; i < CMHSIZ; i++)
545: cmhash[i] = ecmx;
546: cmap[CMHEAD].c_prev = freemem / CLSIZE;
547: cmap[CMHEAD].c_type = CSYS;
548: avefree = freemem;
549: }
550:
551: #ifdef notdef
552: /*
553: * Wait for frame pf to become unlocked
554: * if it is currently locked.
555: */
556: mwait(c)
557: struct cmap *c;
558: {
559:
560: mlock(c);
561: munlock(c);
562: }
563:
564: /*
565: * Lock a page frame.
566: */
567: mlock(c)
568: register struct cmap *c;
569: {
570:
571: while (c->c_lock) {
572: c->c_want = 1;
573: sleep((caddr_t)c, PSWP+1);
574: }
575: c->c_lock = 1;
576: }
577:
578: /*
579: * Unlock a page frame.
580: */
581: munlock(c)
582: register struct cmap *c;
583: {
584:
585: if (c->c_lock == 0)
586: panic("dup page unlock");
587: if (c->c_want) {
588: wakeup((caddr_t)c);
589: c->c_want = 0;
590: }
591: c->c_lock = 0;
592: }
593: #endif
594:
595: /*
596: * Lock a virtual segment.
597: *
598: * For each cluster of pages, if the cluster is not valid,
599: * touch it to fault it in, otherwise just lock page frame.
600: * Called from physio to ensure that the pages
601: * participating in raw i/o are valid and locked.
602: */
603: vslock(base, count)
604: caddr_t base;
605: {
606: register unsigned v;
607: register int npf;
608: register struct pte *pte;
609: register struct cmap *c;
610:
611: #if defined(tahoe)
612: /*
613: * TAHOE I/O drivers may arrive here on raw I/O,
614: * base will be a system address in this case
615: */
616: if (((int)base & KERNBASE) == KERNBASE) /* system addresses */
617: return;
618: #endif
619: v = clbase(btop(base));
620: pte = vtopte(u.u_procp, v);
621: npf = btoc(count + ((int)base & CLOFSET));
622: for (; npf > 0; pte += CLSIZE, v += CLSIZE, npf -= CLSIZE) {
623: retry:
624: if (pte->pg_v) {
625: #ifdef MAPMEM
626: if (pte->pg_fod) /* mapped page */
627: continue;
628: #endif
629: c = &cmap[pgtocm(pte->pg_pfnum)];
630: if (c->c_lock) {
631: MLOCK(c);
632: MUNLOCK(c);
633: goto retry;
634: }
635: MLOCK(c);
636: } else
637: pagein(ctob(v), 1); /* return it locked */
638: }
639: }
640:
641: /*
642: * Unlock a virtual segment.
643: */
644: vsunlock(base, count, rw)
645: caddr_t base;
646: {
647: register struct pte *pte;
648: register struct cmap *c;
649: unsigned v;
650: int npf;
651:
652: #if defined(tahoe)
653: /*
654: * TAHOE I/O drivers may arrive here on raw I/O,
655: * base will be a system address in this case
656: */
657: if (((int)base & KERNBASE) == KERNBASE) /* system addresses */
658: return;
659: #endif
660: v = clbase(btop(base));
661: pte = vtopte(u.u_procp, v);
662: npf = btoc(count + ((int)base & CLOFSET));
663: for (; npf > 0; pte += CLSIZE, npf -= CLSIZE) {
664: #ifdef MAPMEM
665: if (pte->pg_fod && pte->pg_v) /* mapped page */
666: continue;
667: #endif
668: c = &cmap[pgtocm(pte->pg_pfnum)];
669: MUNLOCK(c);
670: if (rw == B_READ) /* Reading from device writes memory */
671: pte->pg_m = 1;
672: }
673: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.