kernel: avoid palloc lock during mmurelease()

Previously, mmurelease() was always called with
palloc spinlock held.

This is unneccesary for some mmurelease()
implementations as they wont release pages
to the palloc pool.

This change removes pagechainhead() and
pagechaindone() and replaces them with just
freepages() call, which aquires the palloc
lock internally as needed.

freepages() avoids holding the palloc lock
while walking the linked list of pages,
avoding some lock contention.
This commit is contained in:
cinap_lenrek 2020-12-22 16:29:55 +01:00
parent 2fb5fbbd73
commit 29f60cace1
13 changed files with 82 additions and 162 deletions

View file

@ -173,17 +173,9 @@ flushmmu(void)
void void
mmurelease(Proc* proc) mmurelease(Proc* proc)
{ {
Page *page, *next;
mmul2empty(proc, 0); mmul2empty(proc, 0);
for(page = proc->mmul2cache; page != nil; page = next){
next = page->next; freepages(proc->mmul2cache, nil, 0);
if(--page->ref)
panic("mmurelease: page->ref %lud", page->ref);
pagechainhead(page);
}
if(proc->mmul2cache != nil)
pagechaindone();
proc->mmul2cache = nil; proc->mmul2cache = nil;
mmul1empty(); mmul1empty();

View file

@ -518,20 +518,10 @@ mmuswitch(Proc *p)
void void
mmurelease(Proc *p) mmurelease(Proc *p)
{ {
Page *t;
mmuswitch(nil); mmuswitch(nil);
mmufree(p); mmufree(p);
freepages(p->mmufree, nil, 0);
if((t = p->mmufree) != nil){ p->mmufree = nil;
do {
p->mmufree = t->next;
if(--t->ref != 0)
panic("mmurelease: bad page ref");
pagechainhead(t);
} while((t = p->mmufree) != nil);
pagechaindone();
}
} }
void void

View file

@ -197,23 +197,21 @@ flushmmu(void)
void void
mmurelease(Proc *proc) mmurelease(Proc *proc)
{ {
Page *p, *n; Page *p;
if(islo())
panic("mmurelease: islo");
l1switch(&m->l1, 0); l1switch(&m->l1, 0);
if(proc->kmaptable != nil){ if((p = proc->kmaptable) != nil){
if(p->ref != 1)
panic("mmurelease: kmap ref %ld", p->ref);
if(proc->l1 == nil) if(proc->l1 == nil)
panic("mmurelease: no l1"); panic("mmurelease: no l1");
if(decref(proc->kmaptable) != 0)
panic("mmurelease: kmap ref %ld", proc->kmaptable->ref);
if(proc->nkmap) if(proc->nkmap)
panic("mmurelease: nkmap %d", proc->nkmap); panic("mmurelease: nkmap %d", proc->nkmap);
if(PPN(proc->l1->va[L1X(KMAP)]) != proc->kmaptable->pa) if(PPN(proc->l1->va[L1X(KMAP)]) != p->pa)
panic("mmurelease: bad kmap l2 %#.8lux kmap %#.8lux", proc->l1->va[L1X(KMAP)], proc->kmaptable->pa); panic("mmurelease: bad kmap l2 %#.8lux kmap %#.8lux", proc->l1->va[L1X(KMAP)], p->pa);
proc->l1->va[L1X(KMAP)] = 0; proc->l1->va[L1X(KMAP)] = 0;
pagechainhead(proc->kmaptable); p->next = proc->mmufree;
proc->mmufree = p;
proc->kmaptable = nil; proc->kmaptable = nil;
} }
if(proc->l1 != nil){ if(proc->l1 != nil){
@ -221,14 +219,7 @@ mmurelease(Proc *proc)
l1free(proc->l1); l1free(proc->l1);
proc->l1 = nil; proc->l1 = nil;
} }
for(p = proc->mmufree; p != nil; p = n){ freepages(proc->mmufree, nil, 0);
n = p->next;
if(decref(p) != 0)
panic("mmurelease: p->ref %ld", p->ref);
pagechainhead(p);
}
if(proc->mmufree != nil)
pagechaindone();
proc->mmufree = nil; proc->mmufree = nil;
} }

View file

@ -252,20 +252,12 @@ flushmmu(void)
void void
mmurelease(Proc* proc) mmurelease(Proc* proc)
{ {
Page *page, *next;
/* write back dirty and invalidate l1 caches */ /* write back dirty and invalidate l1 caches */
cacheuwbinv(); cacheuwbinv();
mmul2empty(proc, 0); mmul2empty(proc, 0);
for(page = proc->mmul2cache; page != nil; page = next){
next = page->next; freepages(proc->mmul2cache, nil, 0);
if(--page->ref)
panic("mmurelease: page->ref %lud", page->ref);
pagechainhead(page);
}
if(proc->mmul2cache != nil)
pagechaindone();
proc->mmul2cache = nil; proc->mmul2cache = nil;
mmul1empty(); mmul1empty();

View file

@ -234,20 +234,12 @@ flushmmu(void)
void void
mmurelease(Proc* proc) mmurelease(Proc* proc)
{ {
Page *page, *next;
/* write back dirty and invalidate l1 caches */ /* write back dirty and invalidate l1 caches */
cacheuwbinv(); cacheuwbinv();
mmul2empty(proc, 0); mmul2empty(proc, 0);
for(page = proc->mmul2cache; page != nil; page = next){
next = page->next; freepages(proc->mmul2cache, nil, 0);
if(--page->ref)
panic("mmurelease: page->ref %ld", page->ref);
pagechainhead(page);
}
if(proc->mmul2cache != nil)
pagechaindone();
proc->mmul2cache = nil; proc->mmul2cache = nil;
mmul1empty(); mmul1empty();

View file

@ -320,54 +320,48 @@ mmuswitch(Proc* proc)
* cleaning any user entries in the pdb (proc->mmupdb); * cleaning any user entries in the pdb (proc->mmupdb);
* if there's a pdb put it in the cache of pre-initialised pdb's * if there's a pdb put it in the cache of pre-initialised pdb's
* for this processor (m->pdbpool) or on the process' free list; * for this processor (m->pdbpool) or on the process' free list;
* finally, place any pages freed back into the free pool (palloc). * finally, place any pages freed back into the free pool (freepages).
* This routine is only called from schedinit() with palloc locked.
*/ */
void void
mmurelease(Proc* proc) mmurelease(Proc* proc)
{ {
Page *page, *next;
ulong *pdb; ulong *pdb;
Page *page;
if(islo())
panic("mmurelease: islo");
taskswitch(PADDR(m->pdb), (ulong)m + BY2PG); taskswitch(PADDR(m->pdb), (ulong)m + BY2PG);
if(proc->kmaptable != nil){ if((page = proc->kmaptable) != nil){
if(page->ref != 1)
panic("mmurelease: kmap ref %ld", page->ref);
if(proc->mmupdb == nil) if(proc->mmupdb == nil)
panic("mmurelease: no mmupdb"); panic("mmurelease: no mmupdb");
if(--proc->kmaptable->ref != 0)
panic("mmurelease: kmap ref %ld", proc->kmaptable->ref);
if(proc->nkmap) if(proc->nkmap)
panic("mmurelease: nkmap %d", proc->nkmap); panic("mmurelease: nkmap %d", proc->nkmap);
/* /*
* remove kmaptable from pdb before putting pdb up for reuse. * remove kmaptable from pdb before putting pdb up for reuse.
*/ */
pdb = tmpmap(proc->mmupdb); pdb = tmpmap(proc->mmupdb);
if(PPN(pdb[PDX(KMAP)]) != proc->kmaptable->pa) if(PPN(pdb[PDX(KMAP)]) != page->pa)
panic("mmurelease: bad kmap pde %#.8lux kmap %#.8lux", panic("mmurelease: bad kmap pde %#.8lux kmap %#.8lux",
pdb[PDX(KMAP)], proc->kmaptable->pa); pdb[PDX(KMAP)], page->pa);
pdb[PDX(KMAP)] = 0; pdb[PDX(KMAP)] = 0;
tmpunmap(pdb); tmpunmap(pdb);
/* /*
* move kmaptable to free list. * move kmaptable to free list.
*/ */
pagechainhead(proc->kmaptable); page->next = proc->mmufree;
proc->mmufree = page;
proc->kmaptable = nil; proc->kmaptable = nil;
} }
if(proc->mmupdb != nil){ if((page = proc->mmupdb) != nil){
mmuptefree(proc); mmuptefree(proc);
mmupdbfree(proc, proc->mmupdb); mmupdbfree(proc, page);
proc->mmupdb = nil; proc->mmupdb = nil;
} }
for(page = proc->mmufree; page != nil; page = next){ if((page = proc->mmufree) != nil){
next = page->next; freepages(page, nil, 0);
if(--page->ref != 0) proc->mmufree = nil;
panic("mmurelease: page->ref %ld", page->ref);
pagechainhead(page);
} }
if(proc->mmufree != nil)
pagechaindone();
proc->mmufree = nil;
if(proc->ldt != nil){ if(proc->ldt != nil){
free(proc->ldt); free(proc->ldt);
proc->ldt = nil; proc->ldt = nil;

View file

@ -469,7 +469,7 @@ fixedseg(uintptr va, ulong len)
{ {
KMap *k; KMap *k;
Segment *s; Segment *s;
Page **f, *p, *l, *h; Page **f, *p, *l, *h, *t;
ulong n, i; ulong n, i;
int color; int color;
@ -492,12 +492,13 @@ fixedseg(uintptr va, ulong len)
continue; continue;
i = 0; i = 0;
h = nil; h = t = nil;
f = &palloc.head; f = &palloc.head;
while((p = *f) != nil){ while((p = *f) != nil){
if(p > &l[-len] && p <= l){ if(p > &l[-len] && p <= l){
*f = p->next; *f = p->next;
p->next = h; if((p->next = h) == nil)
t = p;
h = p; h = p;
if(++i < len) if(++i < len)
continue; continue;
@ -505,15 +506,15 @@ fixedseg(uintptr va, ulong len)
} }
f = &p->next; f = &p->next;
} }
palloc.freecount -= i;
if(i != len){ if(i != len){
while((p = h) != nil){ if(h != nil){
h = h->next; t->next = palloc.head;
pagechainhead(p); palloc.head = h;
} }
goto Retry; goto Retry;
} }
palloc.freecount -= i;
unlock(&palloc); unlock(&palloc);
p = &l[-len]; p = &l[-len];

View file

@ -11,7 +11,7 @@ void
pageinit(void) pageinit(void)
{ {
int color, i, j; int color, i, j;
Page *p; Page *p, **t;
Pallocmem *pm; Pallocmem *pm;
vlong m, v, u; vlong m, v, u;
@ -29,8 +29,12 @@ pageinit(void)
} }
color = 0; color = 0;
palloc.freecount = 0;
palloc.head = nil; palloc.head = nil;
t = &palloc.head;
p = palloc.pages; p = palloc.pages;
for(i=0; i<nelem(palloc.mem); i++){ for(i=0; i<nelem(palloc.mem); i++){
pm = &palloc.mem[i]; pm = &palloc.mem[i];
for(j=0; j<pm->npage; j++){ for(j=0; j<pm->npage; j++){
@ -40,7 +44,8 @@ pageinit(void)
continue; continue;
p->color = color; p->color = color;
color = (color+1)%NCOLOR; color = (color+1)%NCOLOR;
pagechainhead(p); *t = p, t = &p->next;
palloc.freecount++;
p++; p++;
} }
} }
@ -65,15 +70,7 @@ pageinit(void)
print("%lldM swap\n", v/(1024*1024)); print("%lldM swap\n", v/(1024*1024));
} }
void static void
pagechainhead(Page *p)
{
p->next = palloc.head;
palloc.head = p;
palloc.freecount++;
}
void
pagechaindone(void) pagechaindone(void)
{ {
if(palloc.pwait[0].p != nil && wakeup(&palloc.pwait[0]) != nil) if(palloc.pwait[0].p != nil && wakeup(&palloc.pwait[0]) != nil)
@ -85,11 +82,23 @@ pagechaindone(void)
void void
freepages(Page *head, Page *tail, ulong np) freepages(Page *head, Page *tail, ulong np)
{ {
assert(palloc.Lock.p == up); if(head == nil)
return;
if(tail == nil){
tail = head;
for(np = 1;; np++){
tail->ref = 0;
if(tail->next == nil)
break;
tail = tail->next;
}
}
lock(&palloc);
tail->next = palloc.head; tail->next = palloc.head;
palloc.head = head; palloc.head = head;
palloc.freecount += np; palloc.freecount += np;
pagechaindone(); pagechaindone();
unlock(&palloc);
} }
ulong ulong
@ -138,11 +147,8 @@ pagereclaim(Image *i)
} }
putimage(i); putimage(i);
if(np > 0){ if(np > 0)
lock(&palloc);
freepages(fh, ft, np); freepages(fh, ft, np);
unlock(&palloc);
}
return np; return np;
} }
@ -237,11 +243,8 @@ putpage(Page *p)
decref(p); decref(p);
return; return;
} }
if(decref(p) == 0){ if(decref(p) == 0)
lock(&palloc);
freepages(p, p, 1); freepages(p, p, 1);
unlock(&palloc);
}
} }
void void

View file

@ -218,8 +218,6 @@ int okaddr(uintptr, ulong, int);
int openmode(ulong); int openmode(ulong);
Block* packblock(Block*); Block* packblock(Block*);
Block* padblock(Block*, int); Block* padblock(Block*, int);
void pagechaindone(void);
void pagechainhead(Page*);
void pageinit(void); void pageinit(void);
ulong pagereclaim(Image*); ulong pagereclaim(Image*);
void panic(char*, ...); void panic(char*, ...);

View file

@ -81,27 +81,21 @@ schedinit(void) /* never returns */
case Moribund: case Moribund:
up->state = Dead; up->state = Dead;
edfstop(up); edfstop(up);
if(up->edf != nil) if(up->edf != nil){
free(up->edf); free(up->edf);
up->edf = nil; up->edf = nil;
}
/*
* Holding locks from pexit:
* procalloc
* palloc
*/
mmurelease(up); mmurelease(up);
unlock(&palloc);
updatecpu(up); lock(&procalloc);
up->mach = nil; up->mach = nil;
up->qnext = procalloc.free; up->qnext = procalloc.free;
procalloc.free = up; procalloc.free = up;
/* proc is free now, make sure unlock() wont touch it */ /* proc is free now, make sure unlock() wont touch it */
up = procalloc.Lock.p = nil; up = procalloc.Lock.p = nil;
unlock(&procalloc); unlock(&procalloc);
sched(); sched();
} }
coherence(); coherence();
@ -1223,10 +1217,6 @@ pexit(char *exitstr, int freemem)
} }
qunlock(&up->seglock); qunlock(&up->seglock);
/* Sched must not loop for these locks */
lock(&procalloc);
lock(&palloc);
edfstop(up); edfstop(up);
up->state = Moribund; up->state = Moribund;
sched(); sched();

View file

@ -475,20 +475,12 @@ flushmmu(void)
void void
mmurelease(Proc* proc) mmurelease(Proc* proc)
{ {
Page *page, *next;
/* write back dirty and invalidate caches */ /* write back dirty and invalidate caches */
l1cache->wbinv(); l1cache->wbinv();
mmul2empty(proc, 0); mmul2empty(proc, 0);
for(page = proc->mmul2cache; page != nil; page = next){
next = page->next; freepages(proc->mmul2cache, nil, 0);
if(--page->ref)
panic("mmurelease: page->ref %ld", page->ref);
pagechainhead(page);
}
if(proc->mmul2cache != nil)
pagechaindone();
proc->mmul2cache = nil; proc->mmul2cache = nil;
mmul1empty(); mmul1empty();

View file

@ -282,15 +282,8 @@ mmurelease(Proc* proc)
} }
} }
for(page = proc->mmufree; page; page = next){ freepages(proc->mmufree, nil, 0);
next = page->next; proc->mmufree = nil;
if(--page->ref)
panic("mmurelease: page->ref %ld\n", page->ref);
pagechainhead(page);
}
if(proc->mmufree)
pagechaindone();
proc->mmufree = 0;
} }
static Page* static Page*

View file

@ -205,23 +205,22 @@ flushmmu(void)
void void
mmurelease(Proc *proc) mmurelease(Proc *proc)
{ {
Page *p, *n; Page *p;
if(islo())
panic("mmurelease: islo");
l1switch(&m->l1, 0); l1switch(&m->l1, 0);
if(proc->kmaptable != nil){ if((p = proc->kmaptable) != nil){
if(p->ref != 1)
panic("mmurelease: kmap ref %ld", p->ref);
if(proc->l1 == nil) if(proc->l1 == nil)
panic("mmurelease: no l1"); panic("mmurelease: no l1");
if(decref(proc->kmaptable) != 0)
panic("mmurelease: kmap ref %ld", proc->kmaptable->ref);
if(proc->nkmap) if(proc->nkmap)
panic("mmurelease: nkmap %d", proc->nkmap); panic("mmurelease: nkmap %d", proc->nkmap);
if(PPN(proc->l1->va[L1X(KMAP)]) != proc->kmaptable->pa) if(PPN(proc->l1->va[L1X(KMAP)]) != p->pa)
panic("mmurelease: bad kmap l2 %#.8lux kmap %#.8lux", proc->l1->va[L1X(KMAP)], proc->kmaptable->pa); panic("mmurelease: bad kmap l2 %#.8lux kmap %#.8lux", proc->l1->va[L1X(KMAP)], p->pa);
proc->l1->va[L1X(KMAP)] = 0; proc->l1->va[L1X(KMAP)] = 0;
pagechainhead(proc->kmaptable);
p->next = proc->mmufree;
proc->mmufree = p;
proc->kmaptable = nil; proc->kmaptable = nil;
} }
if(proc->l1 != nil){ if(proc->l1 != nil){
@ -229,14 +228,7 @@ mmurelease(Proc *proc)
l1free(proc->l1); l1free(proc->l1);
proc->l1 = nil; proc->l1 = nil;
} }
for(p = proc->mmufree; p != nil; p = n){ freepages(proc->mmufree, nil, 0);
n = p->next;
if(decref(p) != 0)
panic("mmurelease: p->ref %ld", p->ref);
pagechainhead(p);
}
if(proc->mmufree != nil)
pagechaindone();
proc->mmufree = nil; proc->mmufree = nil;
} }