2 #include "../port/lib.h"
6 #include "../port/error.h"
11 static int canflush(Proc*, Segment*);
12 static void executeio(void);
13 static void pageout(Proc*, Segment*);
14 static void pagepte(int, Page**);
15 static void pager(void*);
21 static Chan *swapchan;
22 static uchar *swapbuf;
23 static AESstate *swapkey;
28 static ushort ageclock;
33 while(conf.nswap && conf.nswppo){
34 swapalloc.swmap = xalloc(conf.nswap);
35 if(swapalloc.swmap == nil)
37 iolist = xalloc(conf.nswppo*sizeof(Page*));
39 xfree(swapalloc.swmap);
40 swapalloc.swmap = nil;
45 if(swapalloc.swmap == nil || iolist == nil)
46 conf.nswap = conf.nswppo = 0;
48 swapalloc.top = &swapalloc.swmap[conf.nswap];
49 swapalloc.alloc = swapalloc.swmap;
50 swapalloc.last = swapalloc.swmap;
51 swapalloc.free = conf.nswap;
54 kproc("pager", pager, 0);
63 if(swapalloc.free == 0) {
67 look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last);
69 look = memchr(swapalloc.swmap, 0, swapalloc.last-swapalloc.swmap);
70 *look = 2; /* ref for pte + io transaction */
71 swapalloc.last = look;
74 return (look-swapalloc.swmap) * BY2PG;
83 idx = &swapalloc.swmap[((uintptr)p)/BY2PG];
85 panic("putswap %#p ref == 0", p);
88 if(swapalloc.xref == 0)
89 panic("putswap %#p xref == 0", p);
91 if(--swapalloc.xref == 0) {
92 for(idx = swapalloc.swmap; idx < swapalloc.top; idx++) {
112 idx = &swapalloc.swmap[((uintptr)p)/BY2PG];
117 swapalloc.xref += 255;
123 swapcount(uintptr daddr)
125 return swapalloc.swmap[daddr/BY2PG];
131 wakeup(&swapalloc.r);
140 if((np = pagereclaim(&fscache, 1000)) > 0) {
141 if(0) print("reclaim: %lud fscache\n", np);
142 } else if((np = pagereclaim(&swapimage, 1000)) > 0) {
143 if(0) print("reclaim: %lud swap\n", np);
144 } else if((np = imagereclaim(1000)) > 0) {
145 if(0) print("reclaim: %lud image\n", np);
148 return 1; /* have pages, done */
150 return 0; /* didnt reclaim, need to swap */
167 up->psstate = "Reclaim";
169 up->psstate = "Idle";
170 wakeup(&palloc.pwait[0]);
171 wakeup(&palloc.pwait[1]);
172 sleep(&swapalloc.r, needpages, nil);
176 if(swapimage.c == nil || swapalloc.free == 0){
179 killbig("out of memory");
186 if(++x >= conf.nproc){
192 } while(p->state == Dead || p->noswap || !canqlock(&p->seglock));
193 up->psstate = "Pageout";
194 for(i = 0; i < NSEG; i++) {
195 if((s = p->seg[i]) != nil) {
196 switch(s->type&SG_TYPE) {
211 qunlock(&p->seglock);
221 pageout(Proc *p, Segment *s)
228 if(!canqlock(s)) /* We cannot afford to wait, we will surely deadlock */
231 if(!canflush(p, s) /* Able to invalidate all tlbs with references */
238 /* Pass through the pte tables looking for memory pages to swap out */
239 type = s->type&SG_TYPE;
241 for(i = 0; i < size; i++) {
245 for(pg = l->first; pg <= l->last; pg++) {
249 if(entry->modref & PG_REF) {
250 entry->modref &= ~PG_REF;
251 entry->refage = ageclock;
254 age = (short)(ageclock - entry->refage);
266 canflush(Proc *p, Segment *s)
270 if(incref(s) == 2) /* Easy if we are the only user */
274 * Now we must do hardwork to ensure all processes which have tlb
275 * entries for this segment will be flushed if we succeed in paging it out
277 for(x = 0; x < conf.nproc; x++){
281 for(i = 0; i < NSEG; i++){
291 pagepte(int type, Page **pg)
298 case SG_TEXT: /* Revert to demand load */
307 if(ioptr >= conf.nswppo)
311 * get a new swap address with swapcount 2, one for the pte
312 * and one extra ref for us while we write the page to disk
318 /* clear any pages referring to it from the cache */
319 cachedel(&swapimage, daddr);
321 /* forget anything that it used to cache */
325 * enter it into the cache so that a fault happening
326 * during the write will grab the page from the cache
327 * rather than one partially written to the disk
330 cachepage(outp, &swapimage);
331 *pg = (Page*)(daddr|PG_ONSWAP);
333 /* Add page to IO transaction list */
334 iolist[ioptr++] = outp;
345 for(i = j = 0; i < ioptr; i++) {
348 assert(outp->ref > 0);
349 assert(outp->image == &swapimage);
350 assert(outp->daddr != ~0);
352 /* only write when swap address still in use */
353 if(swapcount(outp->daddr) > 1){
354 Chan *c = swapimage.c;
355 KMap *k = kmap(outp);
361 if(devtab[c->type]->write(c, (char*)VA(k), BY2PG, outp->daddr) != BY2PG)
367 /* drop our extra swap reference */
368 putswap((Page*)outp->daddr);
370 /* Free up the page after I/O */
374 if(j) print("executeio (%lud/%lud): %s\n", j, i, up->errstr);
380 return palloc.freecount < swapalloc.headroom;
386 uchar buf[sizeof(Dir)+100];
394 if(swapimage.c != nil) {
395 if(swapalloc.free != conf.nswap)
402 * if this isn't a file, set the swap space
403 * to be at most the size of the partition
405 if(devtab[c->type]->dc != L'M'){
406 n = devtab[c->type]->stat(c, buf, sizeof buf);
407 if(n <= 0 || convM2D(buf, n, &d, nil) == 0)
408 error("stat failed in setswapchan");
409 if(d.length < (vlong)conf.nswppo*BY2PG)
410 error("swap device too small");
411 if(d.length < (vlong)conf.nswap*BY2PG){
412 conf.nswap = d.length/BY2PG;
413 swapalloc.top = &swapalloc.swmap[conf.nswap];
414 swapalloc.free = conf.nswap;
422 swapimage.c = namec("#¶/swapfile", Aopen, ORDWR, 0);
431 static Dirtab swapdir[]={
432 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
433 "swap", {Qswap}, 0, 0664,
434 "swapfile", {Qswapfile}, 0, 0600,
438 swapattach(char *spec)
440 return devattach(L'¶', spec);
444 swapwalk(Chan *c, Chan *nc, char **name, int nname)
446 return devwalk(c, nc, name, nname, swapdir, nelem(swapdir), devgen);
450 swapstat(Chan *c, uchar *dp, int n)
452 return devstat(c, dp, n, swapdir, nelem(swapdir), devgen);
456 swapopen(Chan *c, int omode)
460 switch((ulong)c->qid.path){
462 if(!iseve() || omode != ORDWR)
464 if(swapimage.c != nil)
469 c->mode = openmode(omode);
473 swapbuf = mallocalign(BY2PG, BY2PG, 0, 0);
474 swapkey = secalloc(sizeof(AESstate)*2);
475 if(swapbuf == nil || swapkey == nil)
478 genrandom(key, sizeof(key));
479 setupAESstate(&swapkey[0], key, sizeof(key), nil);
480 genrandom(key, sizeof(key));
481 setupAESstate(&swapkey[1], key, sizeof(key), nil);
482 memset(key, 0, sizeof(key));
486 return devopen(c, omode, swapdir, nelem(swapdir), devgen);
492 if((c->flag & COPEN) == 0)
494 switch((ulong)c->qid.path){
507 swapread(Chan *c, void *va, long n, vlong off)
509 char tmp[256]; /* must be >= 18*NUMSIZE (Qswap) */
512 switch((ulong)c->qid.path){
514 return devdirread(c, va, n, swapdir, nelem(swapdir), devgen);
516 reclaim = imagecached() + fscache.pgref + swapimage.pgref;
517 snprint(tmp, sizeof tmp,
523 "%lud/%lud reclaim\n"
524 "%llud/%llud/%llud kernel malloc\n"
525 "%llud/%llud/%llud kernel draw\n"
526 "%llud/%llud/%llud kernel secret\n",
527 (uvlong)conf.npage*BY2PG,
529 conf.npage-conf.upages,
530 palloc.user-palloc.freecount-reclaim, palloc.user,
531 conf.nswap-swapalloc.free, conf.nswap,
532 reclaim, palloc.user,
533 (uvlong)mainmem->curalloc,
534 (uvlong)mainmem->cursize,
535 (uvlong)mainmem->maxsize,
536 (uvlong)imagmem->curalloc,
537 (uvlong)imagmem->cursize,
538 (uvlong)imagmem->maxsize,
539 (uvlong)secrmem->curalloc,
540 (uvlong)secrmem->cursize,
541 (uvlong)secrmem->maxsize);
542 return readstr((ulong)off, va, n, tmp);
546 if(devtab[swapchan->type]->read(swapchan, va, n, off) != n)
548 aes_xts_decrypt(&swapkey[0], &swapkey[1], off, va, va, n);
556 swapwrite(Chan *c, void *va, long n, vlong off)
560 switch((ulong)c->qid.path){
566 memmove(buf, va, n); /* so we can NUL-terminate */
568 /* start a pager if not already started */
569 if(strncmp(buf, "start", 5) == 0)
571 else if(buf[0]>='0' && buf[0]<='9')
572 setswapchan(fdtochan(strtoul(buf, nil, 0), ORDWR, 1, 1));
579 aes_xts_encrypt(&swapkey[0], &swapkey[1], off, va, swapbuf, n);
580 if(devtab[swapchan->type]->write(swapchan, swapbuf, n, off) != n)