swap.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       swap.c (7036B)
       ---
            1 #include        "u.h"
            2 #include        "lib.h"
            3 #include        "mem.h"
            4 #include        "dat.h"
            5 #include        "fns.h"
            6 #include        "error.h"
            7 
            8 static int        canflush(Proc*, Segment*);
            9 static void        executeio(void);
           10 static int        needpages(void *v);
           11 static void        pageout(Proc*, Segment*);
           12 static void        pagepte(int, Page**);
           13 static void        pager(void *v);
           14 
           15         Image         swapimage;
           16 static        Page        **iolist;
           17 static        int        ioptr;
           18 
           19 void
           20 swapinit(void)
           21 {
           22         swapalloc.swmap = xalloc(conf.nswap);
           23         swapalloc.top = &swapalloc.swmap[conf.nswap];
           24         swapalloc.alloc = swapalloc.swmap;
           25         swapalloc.last = swapalloc.swmap;
           26         swapalloc.free = conf.nswap;
           27         iolist = xalloc(conf.nswppo*sizeof(Page*));
           28         if(swapalloc.swmap == 0 || iolist == 0)
           29                 panic("swapinit: not enough memory");
           30 
           31         swapimage.notext = 1;
           32 }
           33 
           34 ulong
           35 newswap(void)
           36 {
           37         uchar *look;
           38 
           39         lock(&swapalloc.lk);
           40 
           41         if(swapalloc.free == 0){
           42                 unlock(&swapalloc.lk);
           43                 return ~0;
           44         }
           45 
           46         look = memchr(swapalloc.last, 0, swapalloc.top-swapalloc.last);
           47         if(look == 0)
           48                 panic("inconsistent swap");
           49 
           50         *look = 1;
           51         swapalloc.last = look;
           52         swapalloc.free--;
           53         unlock(&swapalloc.lk);
           54         return (look-swapalloc.swmap) * BY2PG;
           55 }
           56 
           57 void
           58 putswap(Page *p)
           59 {
           60         uchar *idx;
           61 
           62         lock(&swapalloc.lk);
           63         idx = &swapalloc.swmap[((ulong)p)/BY2PG];
           64         if(--(*idx) == 0) {
           65                 swapalloc.free++;
           66                 if(idx < swapalloc.last)
           67                         swapalloc.last = idx;
           68         }
           69         if(*idx >= 254)
           70                 panic("putswap %#p == %ud", p, *idx);
           71         unlock(&swapalloc.lk);
           72 }
           73 
           74 void
           75 dupswap(Page *p)
           76 {
           77         lock(&swapalloc.lk);
           78         if(++swapalloc.swmap[((ulong)p)/BY2PG] == 0)
           79                 panic("dupswap");
           80         unlock(&swapalloc.lk);
           81 }
           82 
           83 int
           84 swapcount(ulong daddr)
           85 {
           86         return swapalloc.swmap[daddr/BY2PG];
           87 }
           88 
           89 void
           90 kickpager(void)
           91 {
           92         static int started;
           93 
           94         if(started)
           95                 wakeup(&swapalloc.r);
           96         else {
           97                 kproc("pager", pager, 0);
           98                 started = 1;
           99         }
          100 }
          101 
          102 static void
          103 pager(void *junk)
          104 {
          105         int i;
          106         Segment *s;
          107         Proc *p, *ep;
          108 
          109         if(waserror())
          110                 panic("pager: os error");
          111 
          112         p = proctab(0);
          113         ep = &p[conf.nproc];
          114 
          115 loop:
          116         up->psstate = "Idle";
          117         sleep(&swapalloc.r, needpages, 0);
          118 
          119         while(needpages(junk)) {
          120 
          121                 if(swapimage.c) {
          122                         p++;
          123                         if(p >= ep)
          124                                 p = proctab(0);
          125         
          126                         if(p->state == Dead || p->noswap)
          127                                 continue;
          128 
          129                         if(!canqlock(&p->seglock))
          130                                 continue;                /* process changing its segments */
          131 
          132                         for(i = 0; i < NSEG; i++) {
          133                                 if(!needpages(junk)){
          134                                         qunlock(&p->seglock);
          135                                         goto loop;
          136                                 }
          137 
          138                                 if((s = p->seg[i])) {
          139                                         switch(s->type&SG_TYPE) {
          140                                         default:
          141                                                 break;
          142                                         case SG_TEXT:
          143                                                 pageout(p, s);
          144                                                 break;
          145                                         case SG_DATA:
          146                                         case SG_BSS:
          147                                         case SG_STACK:
          148                                         case SG_SHARED:
          149                                                 up->psstate = "Pageout";
          150                                                 pageout(p, s);
          151                                                 if(ioptr != 0) {
          152                                                         up->psstate = "I/O";
          153                                                         executeio();
          154                                                 }
          155                                                 break;
          156                                         }
          157                                 }
          158                         }
          159                         qunlock(&p->seglock);
          160                 }
          161                 else {
          162                         print("out of physical memory; no swap configured\n");
          163                         if(!cpuserver || freebroken() == 0)
          164                                 killbig("out of memory");
          165 
          166                         /* Emulate the old system if no swap channel */
          167                         tsleep(&up->sleep, return0, 0, 5000);
          168                         wakeup(&palloc.r);
          169                 }
          170         }
          171         goto loop;
          172 }
          173 
          174 static void
          175 pageout(Proc *p, Segment *s)
          176 {
          177         int type, i, size;
          178         Pte *l;
          179         Page **pg, *entry;
          180 
          181         if(!canqlock(&s->lk))        /* We cannot afford to wait, we will surely deadlock */
          182                 return;
          183 
          184         if(s->steal) {                /* Protected by /dev/proc */
          185                 qunlock(&s->lk);
          186                 return;
          187         }
          188 
          189         if(!canflush(p, s)) {        /* Able to invalidate all tlbs with references */
          190                 qunlock(&s->lk);
          191                 putseg(s);
          192                 return;
          193         }
          194 
          195         if(waserror()) {
          196                 qunlock(&s->lk);
          197                 putseg(s);
          198                 return;
          199         }
          200 
          201         /* Pass through the pte tables looking for memory pages to swap out */
          202         type = s->type&SG_TYPE;
          203         size = s->mapsize;
          204         for(i = 0; i < size; i++) {
          205                 l = s->map[i];
          206                 if(l == 0)
          207                         continue;
          208                 for(pg = l->first; pg < l->last; pg++) {
          209                         entry = *pg;
          210                         if(pagedout(entry))
          211                                 continue;
          212 
          213                         if(entry->modref & PG_REF) {
          214                                 entry->modref &= ~PG_REF;
          215                                 continue;
          216                         }
          217 
          218                         pagepte(type, pg);
          219 
          220                         if(ioptr >= conf.nswppo)
          221                                 goto out;
          222                 }
          223         }
          224 out:
          225         poperror();
          226         qunlock(&s->lk);
          227         putseg(s);
          228 }
          229 
          230 static int
          231 canflush(Proc *p, Segment *s)
          232 {
          233         int i;
          234         Proc *ep;
          235 
          236         lock(&s->ref.lk);
          237         if(s->ref.ref == 1) {                /* Easy if we are the only user */
          238                 s->ref.ref++;
          239                 unlock(&s->ref.lk);
          240                 return canpage(p);
          241         }
          242         s->ref.ref++;
          243         unlock(&s->ref.lk);
          244 
          245         /* Now we must do hardwork to ensure all processes which have tlb
          246          * entries for this segment will be flushed if we succeed in paging it out
          247          */
          248         p = proctab(0);
          249         ep = &p[conf.nproc];
          250         while(p < ep) {
          251                 if(p->state != Dead) {
          252                         for(i = 0; i < NSEG; i++)
          253                                 if(p->seg[i] == s)
          254                                         if(!canpage(p))
          255                                                 return 0;
          256                 }
          257                 p++;
          258         }
          259         return 1;
          260 }
          261 
          262 static void
          263 pagepte(int type, Page **pg)
          264 {
          265         ulong daddr;
          266         Page *outp;
          267 
          268         outp = *pg;
          269         switch(type) {
          270         case SG_TEXT:                                /* Revert to demand load */
          271                 putpage(outp);
          272                 *pg = 0;
          273                 break;
          274 
          275         case SG_DATA:
          276         case SG_BSS:
          277         case SG_STACK:
          278         case SG_SHARED:
          279                 /*
          280                  *  get a new swap address and clear any pages
          281                  *  referring to it from the cache
          282                  */
          283                 daddr = newswap();
          284                 if(daddr == ~0)
          285                         break;
          286                 cachedel(&swapimage, daddr);
          287 
          288                 lock(&outp->lk);
          289 
          290                 /* forget anything that it used to cache */
          291                 uncachepage(outp);
          292 
          293                 /*
          294                  *  incr the reference count to make sure it sticks around while
          295                  *  being written
          296                  */
          297                 outp->ref++;
          298 
          299                 /*
          300                  *  enter it into the cache so that a fault happening
          301                  *  during the write will grab the page from the cache
          302                  *  rather than one partially written to the disk
          303                  */
          304                 outp->daddr = daddr;
          305                 cachepage(outp, &swapimage);
          306                 *pg = (Page*)(daddr|PG_ONSWAP);
          307                 unlock(&outp->lk);
          308 
          309                 /* Add page to IO transaction list */
          310                 iolist[ioptr++] = outp;
          311                 break;
          312         }
          313 }
          314 
          315 void
          316 pagersummary(void)
          317 {
          318         print("%lud/%lud memory %lud/%lud swap %d iolist\n",
          319                 palloc.user-palloc.freecount,
          320                 palloc.user, conf.nswap-swapalloc.free, conf.nswap,
          321                 ioptr);
          322 }
          323 
          324 static void
          325 executeio(void)
          326 {
          327         Page *out;
          328         int i, n;
          329         Chan *c;
          330         char *kaddr;
          331         KMap *k;
          332 
          333         c = swapimage.c;
          334 
          335         for(i = 0; i < ioptr; i++) {
          336                 if(ioptr > conf.nswppo)
          337                         panic("executeio: ioptr %d > %d", ioptr, conf.nswppo);
          338                 out = iolist[i];
          339                 k = kmap(out);
          340                 kaddr = (char*)VA(k);
          341 
          342                 if(waserror())
          343                         panic("executeio: page out I/O error");
          344 
          345                 n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);
          346                 if(n != BY2PG)
          347                         nexterror();
          348 
          349                 kunmap(k);
          350                 poperror();
          351 
          352                 /* Free up the page after I/O */
          353                 lock(&out->lk);
          354                 out->ref--;
          355                 unlock(&out->lk);
          356                 putpage(out);
          357         }
          358         ioptr = 0;
          359 }
          360 
          361 static int
          362 needpages(void *v)
          363 {
          364         return palloc.freecount < swapalloc.headroom;
          365 }
          366 
          367 void
          368 setswapchan(Chan *c)
          369 {
          370         uchar dirbuf[sizeof(Dir)+100];
          371         Dir d;
          372         int n;
          373 
          374         if(swapimage.c) {
          375                 if(swapalloc.free != conf.nswap){
          376                         cclose(c);
          377                         error(Einuse);
          378                 }
          379                 cclose(swapimage.c);
          380         }
          381 
          382         /*
          383          *  if this isn't a file, set the swap space
          384          *  to be at most the size of the partition
          385          */
          386         if(devtab[c->type]->dc != L'M'){
          387                 n = devtab[c->type]->stat(c, dirbuf, sizeof dirbuf);
          388                 if(n <= 0){
          389                         cclose(c);
          390                         error("stat failed in setswapchan");
          391                 }
          392                 convM2D(dirbuf, n, &d, nil);
          393                 if(d.length < conf.nswap*BY2PG){
          394                         conf.nswap = d.length/BY2PG;
          395                         swapalloc.top = &swapalloc.swmap[conf.nswap];
          396                         swapalloc.free = conf.nswap;
          397                 }
          398         }
          399 
          400         swapimage.c = c;
          401 }
          402 
          403 int
          404 swapfull(void)
          405 {
          406         return swapalloc.free < conf.nswap/10;
          407 }