fix kernel: pio()/mfreeseg() race

This commit is contained in:
cinap_lenrek 2011-08-24 14:43:15 +02:00
parent 61a0117ea5
commit cf974eb852
2 changed files with 39 additions and 19 deletions

View file

@ -10,18 +10,21 @@ fault(ulong addr, int read)
{
Segment *s;
char *sps;
int pnd;
if(up == nil)
panic("fault: nil up");
if(up->nlocks.ref)
print("fault: nlocks %ld\n", up->nlocks.ref);
pnd = up->notepending;
sps = up->psstate;
up->psstate = "Fault";
spllo();
m->pfault++;
for(;;) {
spllo();
s = seg(up, addr, 1); /* leaves s->lk qlocked if seg != nil */
if(s == 0) {
up->psstate = sps;
@ -36,9 +39,18 @@ fault(ulong addr, int read)
if(fixfault(s, addr, read, 1) == 0)
break;
splhi();
switch(up->procctl){
case Proc_exitme:
case Proc_exitbig:
procctl(up);
}
}
up->psstate = sps;
up->notepending |= pnd;
return 0;
}
@ -267,10 +279,17 @@ retry:
/* another process did it for me */
putpage(new);
goto done;
} else {
} else if(*p) {
/* another process and the pager got in */
putpage(new);
goto retry;
} else {
/* another process segfreed the page */
k = kmap(new);
memset((void*)VA(k), 0, ask);
kunmap(k);
*p = new;
goto done;
}
}

View file

@ -123,7 +123,7 @@ newpage(int clear, Segment **s, ulong va)
Page *p;
KMap *k;
uchar ct;
int i, hw, dontalloc, color;
int i, hw, color;
lock(&palloc);
color = getpgcolor(va);
@ -135,23 +135,22 @@ newpage(int clear, Segment **s, ulong va)
break;
unlock(&palloc);
dontalloc = 0;
if(s && *s) {
if(s)
qunlock(&((*s)->lk));
*s = 0;
dontalloc = 1;
if(!waserror()){
eqlock(&palloc.pwait); /* Hold memory requesters here */
if(!waserror()){
kickpager();
tsleep(&palloc.r, ispages, 0, 1000);
poperror();
}
qunlock(&palloc.pwait);
poperror();
}
qlock(&palloc.pwait); /* Hold memory requesters here */
while(waserror()) /* Ignore interrupts */
;
kickpager();
tsleep(&palloc.r, ispages, 0, 1000);
poperror();
qunlock(&palloc.pwait);
/*
* If called from fault and we lost the segment from
@ -159,8 +158,10 @@ newpage(int clear, Segment **s, ulong va)
* a page. Fault will call newpage again when it has
* reacquired the segment locks
*/
if(dontalloc)
if(s){
*s = 0;
return 0;
}
lock(&palloc);
}