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;
45 iolist = xalloc(conf.nswppo*sizeof(Page*));
46 if(swapalloc.swmap == 0 || iolist == 0)
47 panic("swapinit: not enough memory");
58 if(swapalloc.free == 0) {
63 look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last);
65 panic("inconsistent swap");
68 swapalloc.last = look;
71 return (look-swapalloc.swmap) * BY2PG;
80 idx = &swapalloc.swmap[((ulong)p)/BY2PG];
82 panic("putswap %#p ref == 0", p);
85 if(swapalloc.xref == 0)
86 panic("putswap %#p xref == 0", p);
88 if(--swapalloc.xref == 0) {
89 for(idx = swapalloc.swmap; idx < swapalloc.top; idx++) {
93 if(idx < swapalloc.last)
101 if(idx < swapalloc.last)
102 swapalloc.last = idx;
114 idx = &swapalloc.swmap[((ulong)p)/BY2PG];
119 swapalloc.xref += 255;
125 swapcount(ulong daddr)
127 return swapalloc.swmap[daddr/BY2PG];
136 wakeup(&swapalloc.r);
138 kproc("pager", pager, 0);
151 panic("pager: os error");
157 up->psstate = "Idle";
159 sleep(&swapalloc.r, needpages, 0);
161 while(needpages(junk)) {
162 if(swapimage.c && swapalloc.free) {
169 if(p->state == Dead || p->noswap)
172 if(!canqlock(&p->seglock))
173 continue; /* process changing its segments */
175 for(i = 0; i < NSEG; i++) {
176 if(!needpages(junk)){
177 qunlock(&p->seglock);
182 switch(s->type&SG_TYPE) {
192 up->psstate = "Pageout";
202 qunlock(&p->seglock);
204 killbig("out of memory");
205 freebroken(); /* can use the memory */
213 pageout(Proc *p, Segment *s)
220 if(!canqlock(&s->lk)) /* We cannot afford to wait, we will surely deadlock */
223 if(s->steal) { /* Protected by /dev/proc */
228 if(!canflush(p, s)) { /* Able to invalidate all tlbs with references */
240 /* Pass through the pte tables looking for memory pages to swap out */
241 type = s->type&SG_TYPE;
243 for(i = 0; i < size; i++) {
247 for(pg = l->first; pg < l->last; pg++) {
252 if(entry->modref & PG_REF) {
253 entry->modref &= ~PG_REF;
254 entry->gen = genclock;
257 if(genclock < entry->gen)
258 age = ~(entry->gen - genclock);
260 age = genclock - entry->gen;
268 if(ioptr >= conf.nswppo)
279 canflush(Proc *p, Segment *s)
285 if(s->ref == 1) { /* Easy if we are the only user */
293 /* Now we must do hardwork to ensure all processes which have tlb
294 * entries for this segment will be flushed if we succeed in paging it out
299 if(p->state != Dead) {
300 for(i = 0; i < NSEG; i++)
311 pagepte(int type, Page **pg)
318 case SG_TEXT: /* Revert to demand load */
328 * get a new swap address and clear any pages
329 * referring to it from the cache
334 cachedel(&swapimage, daddr);
338 /* forget anything that it used to cache */
342 * incr the reference count to make sure it sticks around while
348 * enter it into the cache so that a fault happening
349 * during the write will grab the page from the cache
350 * rather than one partially written to the disk
353 cachepage(outp, &swapimage);
354 *pg = (Page*)(daddr|PG_ONSWAP);
357 /* Add page to IO transaction list */
358 iolist[ioptr++] = outp;
366 print("%lud/%lud memory %lud/%lud swap %d iolist\n",
367 palloc.user-palloc.freecount,
368 palloc.user, conf.nswap-swapalloc.free, conf.nswap,
373 pageiocomp(void *a, void *b)
379 if(p1->daddr > p2->daddr)
395 qsort(iolist, ioptr, sizeof iolist[0], pageiocomp);
396 for(i = 0; i < ioptr; i++) {
397 if(ioptr > conf.nswppo)
398 panic("executeio: ioptr %d > %d", ioptr, conf.nswppo);
401 kaddr = (char*)VA(k);
404 panic("executeio: page out I/O error");
406 n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);
413 /* Free up the page after I/O */
425 return palloc.freecount < swapalloc.headroom;
431 uchar dirbuf[sizeof(Dir)+100];
436 if(swapalloc.free != conf.nswap){
445 * if this isn't a file, set the swap space
446 * to be at most the size of the partition
448 if(devtab[c->type]->dc != L'M'){
449 n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
452 error("stat failed in setswapchan");
454 convM2D(dirbuf, n, &d, nil);
455 if(d.length < conf.nswap*BY2PG){
456 conf.nswap = d.length/BY2PG;
457 swapalloc.top = &swapalloc.swmap[conf.nswap];
458 swapalloc.free = conf.nswap;
468 return swapalloc.free < conf.nswap/10;