summaryrefslogtreecommitdiff
path: root/sys/src/9/port/fault.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@localhost>2011-08-24 14:43:15 +0200
committercinap_lenrek <cinap_lenrek@localhost>2011-08-24 14:43:15 +0200
commitcf974eb852cb316772b2294a80069dd8f99e19e9 (patch)
treeaac0418fb930417426b850bca7a1ace709acce78 /sys/src/9/port/fault.c
parent61a0117ea5ddf0a17079faf755b4d51cc045c4ae (diff)
fix kernel: pio()/mfreeseg() race
Diffstat (limited to 'sys/src/9/port/fault.c')
-rw-r--r--sys/src/9/port/fault.c23
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;
}
}