xref: /plan9/sys/src/9/port/page.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"../port/error.h"
7 
8 #define	pghash(daddr)	palloc.hash[(daddr>>PGSHIFT)&(PGHSIZE-1)]
9 
10 static	Lock pglock;
11 struct	Palloc palloc;
12 
13 void
14 pageinit(void)
15 {
16 	Page *p;
17 	ulong np, hw, hr, vmem, pmem;
18 
19 	np = palloc.np0+palloc.np1;
20 	palloc.head = xalloc(np*sizeof(Page));
21 	if(palloc.head == 0)
22 		panic("pageinit");
23 
24 	p = palloc.head;
25 	while(palloc.np0 > 0) {
26 		p->prev = p-1;
27 		p->next = p+1;
28 		p->pa = palloc.p0;
29 		palloc.p0 += BY2PG;
30 		palloc.np0--;
31 		p++;
32 	}
33 	while(palloc.np1 > 0) {
34 		p->prev = p-1;
35 		p->next = p+1;
36 		p->pa = palloc.p1;
37 		palloc.p1 += BY2PG;
38 		palloc.np1--;
39 		p++;
40 	}
41 	palloc.tail = p - 1;
42 	palloc.head->prev = 0;
43 	palloc.tail->next = 0;
44 
45 	palloc.user = p - palloc.head;
46 	palloc.freecount = palloc.user;
47 	pmem = palloc.user*BY2PG/1024;
48 	vmem = pmem + (conf.nswap*BY2PG)/1024;
49 
50 	/* Pageing numbers */
51 	swapalloc.highwater = (palloc.freecount*5)/100;
52 	swapalloc.headroom = swapalloc.highwater + (swapalloc.highwater/4);
53 
54 	hw = swapalloc.highwater*BY2PG;
55 	hr = swapalloc.headroom*BY2PG;
56 
57 	print("%lud free pages, %dK bytes, swap %dK, highwater %dK, headroom %dK\n",
58 	palloc.user, pmem, vmem, hw/1024, hr/1024);/**/
59 }
60 
61 Page*
62 newpage(int clear, Segment **s, ulong va)
63 {
64 	Page *p;
65 	KMap *k;
66 	int hw, i, dontalloc;
67 
68 retry:
69 	lock(&palloc);
70 
71 	hw = swapalloc.highwater;
72 	while((palloc.freecount < hw && u->p->kp == 0) || palloc.freecount == 0) {
73 		palloc.wanted++;
74 		unlock(&palloc);
75 		dontalloc = 0;
76 		if(s && *s) {
77 			qunlock(&((*s)->lk));
78 			*s = 0;
79 			dontalloc = 1;
80 		}
81 		qlock(&palloc.pwait);			/* Hold memory requesters here */
82 
83 		while(waserror())			/* Ignore interrupts */
84 			;
85 
86 		kickpager();
87 		tsleep(&palloc.r, ispages, 0, 1000);
88 
89 		poperror();
90 
91 		qunlock(&palloc.pwait);
92 
93 		/*
94 		 * If called from fault and we lost the segment from underneath
95 		 * don't waste time allocating and freeing a page. Fault will call
96 		 * newpage again when it has reacquired the segment locks
97 		 */
98 		if(dontalloc)
99 			return 0;
100 
101 		lock(&palloc);
102 		palloc.wanted--;
103 	}
104 
105 	p = palloc.head;
106 	if(palloc.head = p->next)		/* = Assign */
107 		palloc.head->prev = 0;
108 	else
109 		palloc.tail = 0;
110 
111 	palloc.freecount--;
112 	unlock(&palloc);
113 
114 	lock(p);
115 	if(p->ref != 0) {	/* lookpage has priority on steal */
116 		unlock(p);
117 		goto retry;
118 	}
119 	uncachepage(p);
120 	p->ref++;
121 	p->va = va;
122 	p->modref = 0;
123 	for(i = 0; i < MAXMACH; i++)
124 		p->cachectl[i] = PG_NOFLUSH;
125 	mmunewpage(p);
126 	unlock(p);
127 
128 	if(clear){
129 		k = kmap(p);
130 		memset((void*)VA(k), 0, BY2PG);
131 		kunmap(k);
132 	}
133 
134 	return p;
135 }
136 
137 int
138 ispages(void *p)
139 {
140 	USED(p);
141 	return palloc.freecount >= swapalloc.highwater;
142 }
143 
144 void
145 putpage(Page *p)
146 {
147 	if(onswap(p)) {
148 		putswap(p);
149 		return;
150 	}
151 
152 	lock(p);
153 	if(--p->ref == 0) {
154 		lock(&palloc);
155 		if(p->image && p->image != &swapimage) {
156 			if(palloc.tail) {
157 				p->prev = palloc.tail;
158 				palloc.tail->next = p;
159 			}
160 			else {
161 				palloc.head = p;
162 				p->prev = 0;
163 			}
164 			palloc.tail = p;
165 			p->next = 0;
166 		}
167 		else {
168 			if(palloc.head) {
169 				p->next = palloc.head;
170 				palloc.head->prev = p;
171 			}
172 			else {
173 				palloc.tail = p;
174 				p->next = 0;
175 			}
176 			palloc.head = p;
177 			p->prev = 0;
178 		}
179 
180 		palloc.freecount++;	/* Release people waiting for memory */
181 		if(palloc.r.p != 0)
182 			wakeup(&palloc.r);
183 		unlock(&palloc);
184 	}
185 	unlock(p);
186 }
187 
188 void
189 simpleputpage(Page *pg)			/* Always call with palloc locked */
190 {
191 	if(pg->ref != 1)
192 		panic("simpleputpage");
193 	pg->ref = 0;
194 	palloc.freecount++;
195 	if(palloc.head == 0) {
196 		palloc.head = palloc.tail = pg;
197 		pg->prev = pg->next = 0;
198 		return;
199 	}
200 	pg->next = palloc.head;
201 	palloc.head->prev = pg;
202 	pg->prev = 0;
203 	palloc.head = pg;
204 }
205 
206 void
207 duppage(Page *p)				/* Always call with p locked */
208 {
209 	Page *np;
210 
211 	/* No dup for swap pages */
212 	if(p->image == &swapimage) {
213 		uncachepage(p);
214 		return;
215 	}
216 
217 	lock(&palloc);
218 	/* No freelist cache when memory is very low */
219 	if(palloc.freecount < swapalloc.highwater) {
220 		unlock(&palloc);
221 		uncachepage(p);
222 		return;
223 	}
224 
225 	np = palloc.head;		/* Allocate a new page from freelist */
226 	if(palloc.head = np->next)	/* = Assign */
227 		palloc.head->prev = 0;
228 	else
229 		palloc.tail = 0;
230 
231 	if(palloc.tail) {		/* Link back onto tail to give us lru */
232 		np->prev = palloc.tail;
233 		palloc.tail->next = np;
234 		np->next = 0;
235 		palloc.tail = np;
236 	}
237 	else {
238 		palloc.head = palloc.tail = np;
239 		np->prev = np->next = 0;
240 	}
241 
242 	unlock(&palloc);
243 
244 	lock(np);				/* Cache the new version */
245 	if(np->ref != 0) {			/* Stolen by lookpage */
246 		uncachepage(p);
247 		unlock(np);
248 		return;
249 	}
250 
251 	uncachepage(np);
252 	np->va = p->va;
253 	np->daddr = p->daddr;
254 	mmunewpage(np);
255 	copypage(p, np);
256 	cachepage(np, p->image);
257 	unlock(np);
258 	uncachepage(p);
259 }
260 
261 void
262 copypage(Page *f, Page *t)
263 {
264 	KMap *ks, *kd;
265 
266 	ks = kmap(f);
267 	kd = kmap(t);
268 	memmove((void*)VA(kd), (void*)VA(ks), BY2PG);
269 	kunmap(ks);
270 	kunmap(kd);
271 }
272 
273 void
274 uncachepage(Page *p)			/* Always called with a locked page */
275 {
276 	Page **l, *f;
277 
278 	if(p->image == 0)
279 		return;
280 
281 	lock(&palloc.hashlock);
282 	l = &pghash(p->daddr);
283 	for(f = *l; f; f = f->hash) {
284 		if(f == p) {
285 			*l = p->hash;
286 			break;
287 		}
288 		l = &f->hash;
289 	}
290 	unlock(&palloc.hashlock);
291 	putimage(p->image);
292 	p->image = 0;
293 }
294 
295 void
296 cachepage(Page *p, Image *i)
297 {
298 	Page **l;
299 
300 	/* If this ever happens it should be fixed by calling
301 	 * uncachepage instead of panic. I think there is a race
302 	 * with pio in which this can happen. Calling uncachepage is
303 	 * correct - I just wanted to see if we got here.
304 	 */
305 	if(p->image)
306 		panic("cachepage");
307 
308 	incref(i);
309 	lock(&palloc.hashlock);
310 	p->image = i;
311 	l = &pghash(p->daddr);
312 	p->hash = *l;
313 	*l = p;
314 	unlock(&palloc.hashlock);
315 }
316 
317 void
318 cachedel(Image *i, ulong daddr)
319 {
320 	Page *f, **l;
321 
322 	lock(&palloc.hashlock);
323 	l = &pghash(daddr);
324 	for(f = *l; f; f = f->hash) {
325 		if(f->image == i && f->daddr == daddr) {
326 			*l = f->hash;
327 			break;
328 		}
329 		l = &f->hash;
330 	}
331 	unlock(&palloc.hashlock);
332 }
333 
334 Page *
335 lookpage(Image *i, ulong daddr)
336 {
337 	Page *f;
338 
339 	lock(&palloc.hashlock);
340 	for(f = pghash(daddr); f; f = f->hash) {
341 		if(f->image == i && f->daddr == daddr) {
342 			unlock(&palloc.hashlock);
343 
344 			lock(f);
345 			if(f->image != i || f->daddr != daddr) {
346 				unlock(f);
347 				return 0;
348 			}
349 
350 			lock(&palloc);
351 			if(++f->ref == 1) {
352 				if(f->prev)
353 					f->prev->next = f->next;
354 				else
355 					palloc.head = f->next;
356 
357 				if(f->next)
358 					f->next->prev = f->prev;
359 				else
360 					palloc.tail = f->prev;
361 				palloc.freecount--;
362 			}
363 			unlock(&palloc);
364 
365 			unlock(f);
366 			return f;
367 		}
368 	}
369 	unlock(&palloc.hashlock);
370 	return 0;
371 }
372 
373 Pte*
374 ptecpy(Pte *old)
375 {
376 	Pte *new;
377 	Page **src, **dst;
378 
379 	new = ptealloc();
380 	dst = &new->pages[old->first-old->pages];
381 	new->first = dst;
382 	for(src = old->first; src <= old->last; src++, dst++)
383 		if(*src) {
384 			if(onswap(*src))
385 				dupswap(*src);
386 			else {
387 				lock(*src);
388 				(*src)->ref++;
389 				unlock(*src);
390 			}
391 			new->last = dst;
392 			*dst = *src;
393 		}
394 
395 	return new;
396 }
397 
398 Pte*
399 ptealloc(void)
400 {
401 	Pte *new;
402 
403 	new = smalloc(sizeof(Pte));
404 	new->first = &new->pages[PTEPERTAB];
405 	new->last = new->pages;
406 	return new;
407 }
408 
409 void
410 freepte(Segment *s, Pte *p)
411 {
412 	int ref;
413 	Page *pt, **pg, **ptop;
414 	void (*fn)(Page*);
415 
416 	switch(s->type&SG_TYPE) {
417 	case SG_PHYSICAL:
418 		fn = s->pseg->pgfree;
419 		ptop = &p->pages[PTEPERTAB];
420 		if(fn) {
421 			for(pg = p->pages; pg < ptop; pg++) {
422 				if(*pg == 0)
423 					continue;
424 				(*fn)(*pg);
425 				*pg = 0;
426 			}
427 			break;
428 		}
429 		for(pg = p->pages; pg < ptop; pg++) {
430 			pt = *pg;
431 			if(pt == 0)
432 				continue;
433 			lock(pt);
434 			ref = --pt->ref;
435 			unlock(pt);
436 			if(ref == 0)
437 				free(pt);
438 		}
439 		break;
440 	default:
441 		for(pg = p->first; pg <= p->last; pg++)
442 			if(*pg) {
443 				putpage(*pg);
444 				*pg = 0;
445 			}
446 	}
447 	free(p);
448 }
449