]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/port/page.c
devmnt: deal with partial response for Tversion request in mntversion()
[plan9front.git] / sys / src / 9 / port / page.c
index 17466ec7a2aa266dad67145b1f05ad066d0861cf..85406f4afe34b7984597d4c5c5c57b54d6e0083c 100644 (file)
@@ -5,9 +5,7 @@
 #include       "fns.h"
 #include       "../port/error.h"
 
-#define        pghash(daddr)   palloc.hash[(daddr>>PGSHIFT)&(PGHSIZE-1)]
-
-struct Palloc palloc;
+Palloc palloc;
 
 void
 pageinit(void)
@@ -15,39 +13,41 @@ pageinit(void)
        int color, i, j;
        Page *p;
        Pallocmem *pm;
-       ulong m, np, k, vkb, pkb;
+       vlong m, v, u;
 
-       np = 0;
-       for(i=0; i<nelem(palloc.mem); i++){
-               pm = &palloc.mem[i];
-               np += pm->npage;
+       if(palloc.pages == nil){
+               ulong np;
+
+               np = 0;
+               for(i=0; i<nelem(palloc.mem); i++){
+                       pm = &palloc.mem[i];
+                       np += pm->npage;
+               }
+               palloc.pages = xalloc(np*sizeof(Page));
+               if(palloc.pages == nil)
+                       panic("pageinit");
        }
-       palloc.pages = xalloc(np*sizeof(Page));
-       if(palloc.pages == 0)
-               panic("pageinit");
 
        color = 0;
-       palloc.head = palloc.pages;
-       p = palloc.head;
+       palloc.head = nil;
+       p = palloc.pages;
        for(i=0; i<nelem(palloc.mem); i++){
                pm = &palloc.mem[i];
                for(j=0; j<pm->npage; j++){
-                       p->prev = p-1;
-                       p->next = p+1;
+                       memset(p, 0, sizeof *p);
                        p->pa = pm->base+j*BY2PG;
+                       if(cankaddr(p->pa) && (KADDR(p->pa) == nil || KADDR(p->pa) == (void*)-BY2PG))
+                               continue;
                        p->color = color;
-                       palloc.freecount++;
                        color = (color+1)%NCOLOR;
+                       pagechainhead(p);
                        p++;
                }
        }
-       palloc.tail = p - 1;
-       palloc.head->prev = 0;
-       palloc.tail->next = 0;
 
        palloc.user = p - palloc.pages;
-       pkb = palloc.user*BY2PG/1024;
-       vkb = pkb + (conf.nswap*BY2PG)/1024;
+       u = palloc.user*BY2PG;
+       v = u + conf.nswap*BY2PG;
 
        /* Paging numbers */
        swapalloc.highwater = (palloc.user*5)/100;
@@ -57,98 +57,127 @@ pageinit(void)
        for(i=0; i<nelem(conf.mem); i++)
                if(conf.mem[i].npage)
                        m += conf.mem[i].npage*BY2PG;
-       k = PGROUND(end - (char*)KTZERO);
-       print("%ldM memory: ", (m+k+1024*1024-1)/(1024*1024));
-       print("%ldM kernel data, ", (m+k-pkb*1024+1024*1024-1)/(1024*1024));
-       print("%ldM user, ", pkb/1024);
-       print("%ldM swap\n", vkb/1024);
-}
+       m += PGROUND(end - (char*)KTZERO);
 
-static void
-pageunchain(Page *p)
-{
-       if(canlock(&palloc))
-               panic("pageunchain (palloc %p)", &palloc);
-       if(p->prev)
-               p->prev->next = p->next;
-       else
-               palloc.head = p->next;
-       if(p->next)
-               p->next->prev = p->prev;
-       else
-               palloc.tail = p->prev;
-       p->prev = p->next = nil;
-       palloc.freecount--;
+       print("%lldM memory: ", (m+1024*1024-1)/(1024*1024));
+       print("%lldM kernel data, ", (m-u+1024*1024-1)/(1024*1024));
+       print("%lldM user, ", u/(1024*1024));
+       print("%lldM swap\n", v/(1024*1024));
 }
 
 void
-pagechaintail(Page *p)
+pagechainhead(Page *p)
 {
-       if(canlock(&palloc))
-               panic("pagechaintail");
-       if(palloc.tail) {
-               p->prev = palloc.tail;
-               palloc.tail->next = p;
-       }
-       else {
-               palloc.head = p;
-               p->prev = 0;
-       }
-       palloc.tail = p;
-       p->next = 0;
+       p->next = palloc.head;
+       palloc.head = p;
        palloc.freecount++;
 }
 
 void
-pagechainhead(Page *p)
+pagechaindone(void)
 {
-       if(canlock(&palloc))
-               panic("pagechainhead");
-       if(palloc.head) {
-               p->next = palloc.head;
-               palloc.head->prev = p;
+       if(palloc.pwait[0].p != nil && wakeup(&palloc.pwait[0]) != nil)
+               return;
+       if(palloc.pwait[1].p != nil)
+               wakeup(&palloc.pwait[1]);
+}
+
+static void
+freepages(Page *head, Page *tail, ulong np)
+{
+       lock(&palloc);
+       tail->next = palloc.head;
+       palloc.head = head;
+       palloc.freecount += np;
+       pagechaindone();
+       unlock(&palloc);
+}
+
+ulong
+pagereclaim(Image *i, ulong pages)
+{
+       Page **h, **l, **x, *p;
+       Page *fh, *ft;
+       ulong np;
+
+       if(pages == 0)
+               return 0;
+
+       lock(i);
+       if(i->pgref == 0){
+               unlock(i);
+               return 0;
        }
-       else {
-               palloc.tail = p;
-               p->next = 0;
+       incref(i);
+
+       np = 0;
+       fh = ft = nil;
+       for(h = i->pghash; h < &i->pghash[PGHSIZE]; h++){
+               l = h;
+               x = nil;
+               for(p = *l; p != nil; p = p->next){
+                       if(p->ref == 0)
+                               x = l;
+                       l = &p->next;
+               }
+               if(x == nil)
+                       continue;
+
+               p = *x;
+               *x = p->next;
+               p->next = nil;
+               p->image = nil;
+               p->daddr = ~0;
+               i->pgref--;
+               decref(i);
+
+               if(fh == nil)
+                       fh = p;
+               else
+                       ft->next = p;
+               ft = p;
+               if(++np >= pages)
+                       break;
        }
-       palloc.head = p;
-       p->prev = 0;
-       palloc.freecount++;
+       unlock(i);
+       putimage(i);
+
+       if(np > 0)
+               freepages(fh, ft, np);
+
+       return np;
+}
+
+static int
+ispages(void*)
+{
+       return palloc.freecount > swapalloc.highwater || up->noswap && palloc.freecount > 0;
 }
 
 Page*
-newpage(int clear, Segment **s, ulong va)
+newpage(int clear, Segment **s, uintptr va)
 {
-       Page *p;
+       Page *p, **l;
        KMap *k;
-       uchar ct;
-       int i, hw, color;
+       int color;
 
        lock(&palloc);
-       color = getpgcolor(va);
-       hw = swapalloc.highwater;
-       for(;;) {
-               if(palloc.freecount > hw)
-                       break;
-               if(up->kp && palloc.freecount > 0)
-                       break;
-
+       while(!ispages(nil)){
                unlock(&palloc);
-               if(s)
-                       qunlock(&((*s)->lk));
+               if(s != nil)
+                       qunlock(*s);
 
                if(!waserror()){
-                       eqlock(&palloc.pwait);  /* Hold memory requesters here */
+                       Rendezq *q;
 
+                       q = &palloc.pwait[!up->noswap];
+                       eqlock(q);      
                        if(!waserror()){
                                kickpager();
-                               tsleep(&palloc.r, ispages, 0, 1000);
+                               sleep(q, ispages, nil);
                                poperror();
                        }
-
-                       qunlock(&palloc.pwait);
-
+                       qunlock(q);
                        poperror();
                }
 
@@ -158,40 +187,36 @@ newpage(int clear, Segment **s, ulong va)
                 * a page. Fault will call newpage again when it has
                 * reacquired the segment locks
                 */
-               if(s){
-                       *s = 0;
-                       return 0;
+               if(s != nil){
+                       *s = nil;
+                       return nil;
                }
-
                lock(&palloc);
        }
 
        /* First try for our colour */
-       for(p = palloc.head; p; p = p->next)
+       color = getpgcolor(va);
+       l = &palloc.head;
+       for(p = *l; p != nil; p = p->next){
                if(p->color == color)
                        break;
-
-       ct = PG_NOFLUSH;
-       if(p == 0) {
-               p = palloc.head;
-               p->color = color;
-               ct = PG_NEWCOL;
+               l = &p->next;
        }
 
-       pageunchain(p);
+       if(p == nil) {
+               l = &palloc.head;
+               p = *l;
+       }
 
-       lock(p);
-       if(p->ref != 0)
-               panic("newpage: p->ref %d != 0", p->ref);
+       *l = p->next;
+       p->next = nil;
+       palloc.freecount--;
+       unlock(&palloc);
 
-       uncachepage(p);
-       p->ref++;
+       p->ref = 1;
        p->va = va;
        p->modref = 0;
-       for(i = 0; i < MAXMACH; i++)
-               p->cachectl[i] = ct;
-       unlock(p);
-       unlock(&palloc);
+       p->txtflush = 0;
 
        if(clear) {
                k = kmap(p);
@@ -202,12 +227,6 @@ newpage(int clear, Segment **s, ulong va)
        return p;
 }
 
-int
-ispages(void*)
-{
-       return palloc.freecount >= swapalloc.highwater;
-}
-
 void
 putpage(Page *p)
 {
@@ -215,141 +234,12 @@ putpage(Page *p)
                putswap(p);
                return;
        }
-
-       lock(&palloc);
-       lock(p);
-
-       if(p->ref == 0)
-               panic("putpage");
-
-       if(--p->ref > 0) {
-               unlock(p);
-               unlock(&palloc);
+       if(p->image != nil) {
+               decref(p);
                return;
        }
-
-       if(p->image && p->image != &swapimage)
-               pagechaintail(p);
-       else 
-               pagechainhead(p);
-
-       if(palloc.r.p != 0)
-               wakeup(&palloc.r);
-
-       unlock(p);
-       unlock(&palloc);
-}
-
-Page*
-auxpage(void)
-{
-       Page *p;
-
-       lock(&palloc);
-       p = palloc.head;
-       if(palloc.freecount < swapalloc.highwater) {
-               unlock(&palloc);
-               return 0;
-       }
-       pageunchain(p);
-
-       lock(p);
-       if(p->ref != 0)
-               panic("auxpage");
-       p->ref++;
-       uncachepage(p);
-       unlock(p);
-       unlock(&palloc);
-
-       return p;
-}
-
-static int dupretries = 15000;
-
-void
-duppage(Page *p)                               /* Always call with p locked */
-{
-       Page *np;
-       int color;
-       int retries;
-
-       retries = 0;
-retry:
-       /* don't dup pages that are shared or have no image */
-       if(p->ref != 1 || p->image == nil || p->image->notext)
-               return;
-
-       if(retries++ > dupretries){
-               print("duppage %d, up %p\n", retries, up);
-               dupretries += 100;
-               if(dupretries > 100000)
-                       panic("duppage");
-               uncachepage(p);
-               return;
-       }
-
-       /*
-        *  normal lock ordering is to call
-        *  lock(&palloc) before lock(p).
-        *  To avoid deadlock, we have to drop
-        *  our locks and try again. as the page
-        *  is from the image cache, this might
-        *  let someone else come in and grab it
-        *  so we check page ref above.
-        */
-       if(!canlock(&palloc)){
-               unlock(p);
-               if(up)
-                       sched();
-               lock(p);
-               goto retry;
-       }
-
-       /* No freelist cache when memory is very low */
-       if(palloc.freecount < swapalloc.highwater) {
-               unlock(&palloc);
-               uncachepage(p);
-               return;
-       }
-
-       color = getpgcolor(p->va);
-       for(np = palloc.head; np; np = np->next)
-               if(np->color == color)
-                       break;
-
-       /* No page of the correct color */
-       if(np == 0) {
-               unlock(&palloc);
-               uncachepage(p);
-               return;
-       }
-
-       pageunchain(np);
-       pagechaintail(np);
-/*
-* XXX - here's a bug? - np is on the freelist but it's not really free.
-* when we unlock palloc someone else can come in, decide to
-* use np, and then try to lock it.  they succeed after we've 
-* run copypage and cachepage and unlock(np).  then what?
-* they call pageunchain before locking(np), so it's removed
-* from the freelist, but still in the cache because of
-* cachepage below.  if someone else looks in the cache
-* before they remove it, the page will have a nonzero ref
-* once they finally lock(np).
-*/
-       lock(np);
-       if(np->ref != 0)        /* should never happen */
-               panic("duppage: np->ref %d != 0", np->ref);
-       unlock(&palloc);
-
-       /* Cache the new version */
-       uncachepage(np);
-       np->va = p->va;
-       np->daddr = p->daddr;
-       copypage(p, np);
-       cachepage(np, p->image);
-       unlock(np);
-       uncachepage(p);
+       if(decref(p) == 0)
+               freepages(p, p, 1);
 }
 
 void
@@ -365,104 +255,87 @@ copypage(Page *f, Page *t)
 }
 
 void
-uncachepage(Page *p)                   /* Always called with a locked page */
+cachepage(Page *p, Image *i)
 {
-       Page **l, *f;
+       Page **h;
 
-       if(p->image == 0)
-               return;
-
-       lock(&palloc.hashlock);
-       l = &pghash(p->daddr);
-       for(f = *l; f; f = f->hash) {
-               if(f == p) {
-                       *l = p->hash;
-                       break;
-               }
-               l = &f->hash;
-       }
-       unlock(&palloc.hashlock);
-       putimage(p->image);
-       p->image = 0;
-       p->daddr = 0;
+       lock(i);
+       p->image = i;
+       h = &PGHASH(i, p->daddr);
+       p->next = *h;
+       *h = p;
+       incref(i);
+       i->pgref++;
+       unlock(i);
 }
 
 void
-cachepage(Page *p, Image *i)
+uncachepage(Page *p)
 {
-       Page **l;
+       Page **l, *x;
+       Image *i;
 
-       /* If this ever happens it should be fixed by calling
-        * uncachepage instead of panic. I think there is a race
-        * with pio in which this can happen. Calling uncachepage is
-        * correct - I just wanted to see if we got here.
-        */
-       if(p->image)
-               panic("cachepage");
+       i = p->image;
+       if(i == nil)
+               return;
 
-       incref(i);
-       lock(&palloc.hashlock);
-       p->image = i;
-       l = &pghash(p->daddr);
-       p->hash = *l;
-       *l = p;
-       unlock(&palloc.hashlock);
+       lock(i);
+       if(p->image != i){
+               unlock(i);
+               return;
+       }
+       l = &PGHASH(i, p->daddr);
+       for(x = *l; x != nil; x = x->next) {
+               if(x == p){
+                       *l = p->next;
+                       p->next = nil;
+                       p->image = nil;
+                       p->daddr = ~0;
+                       i->pgref--;
+                       unlock(i);
+                       putimage(i);
+                       return;
+               }
+               l = &x->next;
+       }
+       unlock(i);
 }
 
-void
-cachedel(Image *i, ulong daddr)
+Page*
+lookpage(Image *i, uintptr daddr)
 {
-       Page *f, **l;
-
-       lock(&palloc.hashlock);
-       l = &pghash(daddr);
-       for(f = *l; f; f = f->hash) {
-               if(f->image == i && f->daddr == daddr) {
-                       lock(f);
-                       if(f->image == i && f->daddr == daddr){
-                               *l = f->hash;
-                               putimage(f->image);
-                               f->image = 0;
-                               f->daddr = 0;
-                       }
-                       unlock(f);
-                       break;
+       Page *p, **h, **l;
+
+       lock(i);
+       l = h = &PGHASH(i, daddr);
+       for(p = *l; p != nil; p = p->next){
+               if(p->daddr == daddr){
+                       *l = p->next;
+                       p->next = *h;
+                       *h = p;
+                       incref(p);
+                       unlock(i);
+                       return p;
                }
-               l = &f->hash;
+               l = &p->next;
        }
-       unlock(&palloc.hashlock);
+       unlock(i);
+
+       return nil;
 }
 
-Page *
-lookpage(Image *i, ulong daddr)
+void
+cachedel(Image *i, uintptr daddr)
 {
-       Page *f;
-
-       lock(&palloc.hashlock);
-       for(f = pghash(daddr); f; f = f->hash) {
-               if(f->image == i && f->daddr == daddr) {
-                       unlock(&palloc.hashlock);
-
-                       lock(&palloc);
-                       lock(f);
-                       if(f->image != i || f->daddr != daddr) {
-                               unlock(f);
-                               unlock(&palloc);
-                               return 0;
-                       }
-                       if(++f->ref == 1)
-                               pageunchain(f);
-                       unlock(&palloc);
-                       unlock(f);
+       Page *p;
 
-                       return f;
-               }
+       while((p = lookpage(i, daddr)) != nil){
+               uncachepage(p);
+               putpage(p);
        }
-       unlock(&palloc.hashlock);
-
-       return 0;
 }
 
+
 Pte*
 ptecpy(Pte *old)
 {
@@ -473,14 +346,11 @@ ptecpy(Pte *old)
        dst = &new->pages[old->first-old->pages];
        new->first = dst;
        for(src = old->first; src <= old->last; src++, dst++)
-               if(*src) {
+               if(*src != nil) {
                        if(onswap(*src))
                                dupswap(*src);
-                       else {
-                               lock(*src);
-                               (*src)->ref++;
-                               unlock(*src);
-                       }
+                       else
+                               incref(*src);
                        new->last = dst;
                        *dst = *src;
                }
@@ -502,40 +372,25 @@ ptealloc(void)
 void
 freepte(Segment *s, Pte *p)
 {
-       int ref;
-       void (*fn)(Page*);
-       Page *pt, **pg, **ptop;
+       Page **pg, **pe;
+
+       pg = p->first;
+       pe = p->last;
 
        switch(s->type&SG_TYPE) {
        case SG_PHYSICAL:
-               fn = s->pseg->pgfree;
-               ptop = &p->pages[PTEPERTAB];
-               if(fn) {
-                       for(pg = p->pages; pg < ptop; pg++) {
-                               if(*pg == 0)
-                                       continue;
-                               (*fn)(*pg);
-                               *pg = 0;
-                       }
-                       break;
-               }
-               for(pg = p->pages; pg < ptop; pg++) {
-                       pt = *pg;
-                       if(pt == 0)
-                               continue;
-                       lock(pt);
-                       ref = --pt->ref;
-                       unlock(pt);
-                       if(ref == 0)
-                               free(pt);
+               while(pg <= pe){
+                       if(*pg != nil && decref(*pg) == 0)
+                               free(*pg);
+                       pg++;
                }
                break;
        default:
-               for(pg = p->first; pg <= p->last; pg++)
-                       if(*pg) {
+               while(pg <= pe){
+                       if(*pg != nil)
                                putpage(*pg);
-                               *pg = 0;
-                       }
+                       pg++;
+               }
        }
        free(p);
 }
@@ -573,7 +428,7 @@ checkpagerefs(void)
        nwrong = 0;
        for(i=0; i<np; i++){
                if(palloc.pages[i].ref != ref[i]){
-                       iprint("page %#.8lux ref %d actual %lud\n", 
+                       iprint("page %#p ref %ld actual %lud\n", 
                                palloc.pages[i].pa, palloc.pages[i].ref, ref[i]);
                        ref[i] = 1;
                        nwrong++;
@@ -605,7 +460,7 @@ portcountpagerefs(ulong *ref, int print)
                p = proctab(i);
                for(j=0; j<NSEG; j++){
                        s = p->seg[j];
-                       if(s)
+                       if(s != nil)
                                s->mark = 0;
                }
        }
@@ -615,6 +470,8 @@ portcountpagerefs(ulong *ref, int print)
                        s = p->seg[j];
                        if(s == nil || s->mark++)
                                continue;
+                       if((s->type&SG_TYPE) == SG_PHYSICAL)
+                               continue;
                        ns++;
                        for(k=0; k<s->mapsize; k++){
                                pte = s->map[k];
@@ -626,7 +483,7 @@ portcountpagerefs(ulong *ref, int print)
                                                continue;
                                        if(print){
                                                if(ref[pagenumber(entry)])
-                                                       iprint("page %#.8lux in segment %#p\n", entry->pa, s);
+                                                       iprint("page %#p in segment %#p\n", entry->pa, s);
                                                continue;
                                        }
                                        if(ref[pagenumber(entry)]++ == 0)