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 /sys/src/9/port/fault.c | |
parent | 61a0117ea5ddf0a17079faf755b4d51cc045c4ae (diff) |
fix kernel: pio()/mfreeseg() race
Diffstat (limited to 'sys/src/9/port/fault.c')
-rw-r--r-- | sys/src/9/port/fault.c | 23 |
1 files changed, 21 insertions, 2 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; } } |