summaryrefslogtreecommitdiff
path: root/sys/src/9/port/fault.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2012-10-16 14:12:21 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2012-10-16 14:12:21 +0200
commit45b99937be5fe2f2fe485e8769f007086c2809b1 (patch)
treee58256106800de3f81665a7f4ff835dbfcbabb8f /sys/src/9/port/fault.c
parent1335be82768204325323bc9b34601b79c7b47aaf (diff)
kernel: cachedel() lock order, lookpage, cleanup
the lock order of page.Lock -> palloc.hashlock was violated in cachedel() which is called from the pager. change the code to do it in the right oder to prevent deadlock. change lookpage to retry on false hit. i assume that a false hit means: a) we'r low on memory -> cached page got uncached/reused b) duppage() got called on the page, meaning theres another cached copy in the image now. paging in is expensive compared to the hashtable lookup, so i think retrying is better. cleanup fixfault, adding comments.
Diffstat (limited to 'sys/src/9/port/fault.c')
-rw-r--r--sys/src/9/port/fault.c19
1 files changed, 12 insertions, 7 deletions
diff --git a/sys/src/9/port/fault.c b/sys/src/9/port/fault.c
index 7338181bc..47717ed87 100644
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -140,15 +140,20 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
lkp = *pg;
lock(lkp);
- if(lkp->ref < 1)
- panic("fault: lkp->ref %d < 1", lkp->ref);
+ ref = lkp->ref;
+ if(ref == 0)
+ panic("fault %#p ref == 0", lkp);
if(lkp->image == &swapimage)
- ref = lkp->ref + swapcount(lkp->daddr);
- else
- ref = lkp->ref;
- if(ref == 1 && lkp->image){
- /* save a copy of the original for the image cache */
+ ref += swapcount(lkp->daddr);
+ if(ref == 1 && lkp->image) {
+ /*
+ * save a copy of the original for the image cache
+ * and uncache the page. page might temporarily be
+ * unlocked while trying to acquire palloc lock so
+ * recheck ref in case it got grabbed.
+ */
duppage(lkp);
+
ref = lkp->ref;
}
unlock(lkp);