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