2 #include "../port/lib.h"
6 #include "../port/error.h"
8 static int canflush(Proc*, Segment*);
9 static void executeio(void);
10 static int needpages(void*);
11 static void pageout(Proc*, Segment*);
12 static void pagepte(int, Page**);
13 static void pager(void*);
21 static ulong genage, genclock, gencount;
29 genage = gensum / gencount;
32 gensum = gencount = 0;
38 swapalloc.swmap = xalloc(conf.nswap);
39 swapalloc.top = &swapalloc.swmap[conf.nswap];
40 swapalloc.alloc = swapalloc.swmap;
41 swapalloc.last = swapalloc.swmap;
42 swapalloc.free = conf.nswap;
43 iolist = xalloc(conf.nswppo*sizeof(Page*));
44 if(swapalloc.swmap == 0 || iolist == 0)
45 panic("swapinit: not enough memory");
57 if(swapalloc.free == 0){
62 look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last);
64 panic("inconsistent swap");
67 swapalloc.last = look;
70 return (look-swapalloc.swmap) * BY2PG;
79 idx = &swapalloc.swmap[((ulong)p)/BY2PG];
82 if(idx < swapalloc.last)
86 panic("putswap %#p == %ud", p, *idx);
94 if(++swapalloc.swmap[((ulong)p)/BY2PG] == 0)
100 swapcount(ulong daddr)
102 return swapalloc.swmap[daddr/BY2PG];
111 wakeup(&swapalloc.r);
113 kproc("pager", pager, 0);
126 panic("pager: os error");
132 up->psstate = "Idle";
134 sleep(&swapalloc.r, needpages, 0);
136 while(needpages(junk)) {
144 if(p->state == Dead || p->noswap)
147 if(!canqlock(&p->seglock))
148 continue; /* process changing its segments */
150 for(i = 0; i < NSEG; i++) {
151 if(!needpages(junk)){
152 qunlock(&p->seglock);
157 switch(s->type&SG_TYPE) {
167 up->psstate = "Pageout";
177 qunlock(&p->seglock);
179 print("out of memory\n");
180 killbig("out of memory");
181 freebroken(); /* can use the memory */
183 /* Emulate the old system if no swap channel */
185 tsleep(&up->sleep, return0, 0, 5000);
192 pageout(Proc *p, Segment *s)
199 if(!canqlock(&s->lk)) /* We cannot afford to wait, we will surely deadlock */
202 if(s->steal) { /* Protected by /dev/proc */
207 if(!canflush(p, s)) { /* Able to invalidate all tlbs with references */
219 /* Pass through the pte tables looking for memory pages to swap out */
220 type = s->type&SG_TYPE;
222 for(i = 0; i < size; i++) {
226 for(pg = l->first; pg < l->last; pg++) {
231 if(entry->modref & PG_REF) {
232 entry->modref &= ~PG_REF;
233 entry->gen = genclock;
236 if(genclock < entry->gen)
237 age = ~(entry->gen - genclock);
239 age = genclock - entry->gen;
247 if(ioptr >= conf.nswppo)
258 canflush(Proc *p, Segment *s)
264 if(s->ref == 1) { /* Easy if we are the only user */
272 /* Now we must do hardwork to ensure all processes which have tlb
273 * entries for this segment will be flushed if we succeed in paging it out
278 if(p->state != Dead) {
279 for(i = 0; i < NSEG; i++)
290 pagepte(int type, Page **pg)
297 case SG_TEXT: /* Revert to demand load */
307 * get a new swap address and clear any pages
308 * referring to it from the cache
313 cachedel(&swapimage, daddr);
317 /* forget anything that it used to cache */
321 * incr the reference count to make sure it sticks around while
327 * enter it into the cache so that a fault happening
328 * during the write will grab the page from the cache
329 * rather than one partially written to the disk
332 cachepage(outp, &swapimage);
333 *pg = (Page*)(daddr|PG_ONSWAP);
336 /* Add page to IO transaction list */
337 iolist[ioptr++] = outp;
345 print("%lud/%lud memory %lud/%lud swap %d iolist\n",
346 palloc.user-palloc.freecount,
347 palloc.user, conf.nswap-swapalloc.free, conf.nswap,
352 pageiocomp(void *a, void *b)
358 if(p1->daddr > p2->daddr)
374 qsort(iolist, ioptr, sizeof iolist[0], pageiocomp);
375 for(i = 0; i < ioptr; i++) {
376 if(ioptr > conf.nswppo)
377 panic("executeio: ioptr %d > %d", ioptr, conf.nswppo);
380 kaddr = (char*)VA(k);
383 panic("executeio: page out I/O error");
385 n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);
392 /* Free up the page after I/O */
404 return palloc.freecount < swapalloc.headroom;
410 uchar dirbuf[sizeof(Dir)+100];
415 if(swapalloc.free != conf.nswap){
423 * if this isn't a file, set the swap space
424 * to be at most the size of the partition
426 if(devtab[c->type]->dc != L'M'){
427 n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
430 error("stat failed in setswapchan");
432 convM2D(dirbuf, n, &d, nil);
433 if(d.length < conf.nswap*BY2PG){
434 conf.nswap = d.length/BY2PG;
435 swapalloc.top = &swapalloc.swmap[conf.nswap];
436 swapalloc.free = conf.nswap;
446 return swapalloc.free < conf.nswap/10;