diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-08-24 14:43:15 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-08-24 14:43:15 +0200 |
commit | cf974eb852cb316772b2294a80069dd8f99e19e9 (patch) | |
tree | aac0418fb930417426b850bca7a1ace709acce78 | |
parent | 61a0117ea5ddf0a17079faf755b4d51cc045c4ae (diff) | |
download | plan9front-cf974eb852cb316772b2294a80069dd8f99e19e9.tar.xz |
fix kernel: pio()/mfreeseg() race
-rw-r--r-- | sys/src/9/port/fault.c | 23 | ||||
-rw-r--r-- | sys/src/9/port/page.c | 29 |
2 files changed, 36 insertions, 16 deletions
diff --git a/sys/src/9/port/fault.c b/sys/src/9/port/fault.c index b6ae6e456..5854d796c 100644 --- a/sys/src/9/port/fault.c +++ b/sys/src/9/port/fault.c @@ -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; } } diff --git a/sys/src/9/port/page.c b/sys/src/9/port/page.c index b99e3588b..fc5906b9e 100644 --- a/sys/src/9/port/page.c +++ b/sys/src/9/port/page.c @@ -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; - } - qlock(&palloc.pwait); /* Hold memory requesters here */ - while(waserror()) /* Ignore interrupts */ - ; + if(!waserror()){ + eqlock(&palloc.pwait); /* Hold memory requesters here */ - kickpager(); - tsleep(&palloc.r, ispages, 0, 1000); + if(!waserror()){ + kickpager(); + tsleep(&palloc.r, ispages, 0, 1000); + poperror(); + } - poperror(); + qunlock(&palloc.pwait); - qunlock(&palloc.pwait); + poperror(); + } /* * 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); } |