The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/port/swap.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 1458dd5d84d73611238e7f5ec2396675


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.