summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/src/9/port/fault.c19
-rw-r--r--sys/src/9/port/page.c29
2 files changed, 29 insertions, 19 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);
diff --git a/sys/src/9/port/page.c b/sys/src/9/port/page.c
index 17466ec7a..b004152e9 100644
--- a/sys/src/9/port/page.c
+++ b/sys/src/9/port/page.c
@@ -335,7 +335,10 @@ retry:
* from the freelist, but still in the cache because of
* cachepage below. if someone else looks in the cache
* before they remove it, the page will have a nonzero ref
-* once they finally lock(np).
+* once they finally lock(np). This does not happen because
+* newpage, auxpage, duppage and lookpage all lock(&palloc)
+* so while they hold it nobody is going to grab anything
+* from the cache.
*/
lock(np);
if(np->ref != 0) /* should never happen */
@@ -412,23 +415,24 @@ cachepage(Page *p, Image *i)
void
cachedel(Image *i, ulong daddr)
{
- Page *f, **l;
+ Page *f;
+retry:
lock(&palloc.hashlock);
- l = &pghash(daddr);
- for(f = *l; f; f = f->hash) {
+ for(f = pghash(daddr); f; f = f->hash) {
if(f->image == i && f->daddr == daddr) {
+ unlock(&palloc.hashlock);
+
lock(f);
- if(f->image == i && f->daddr == daddr){
- *l = f->hash;
- putimage(f->image);
- f->image = 0;
- f->daddr = 0;
+ if(f->image != i || f->daddr != daddr) {
+ unlock(f);
+ goto retry;
}
+ uncachepage(f);
unlock(f);
- break;
+
+ return;
}
- l = &f->hash;
}
unlock(&palloc.hashlock);
}
@@ -438,6 +442,7 @@ lookpage(Image *i, ulong daddr)
{
Page *f;
+retry:
lock(&palloc.hashlock);
for(f = pghash(daddr); f; f = f->hash) {
if(f->image == i && f->daddr == daddr) {
@@ -448,7 +453,7 @@ lookpage(Image *i, ulong daddr)
if(f->image != i || f->daddr != daddr) {
unlock(f);
unlock(&palloc);
- return 0;
+ goto retry;
}
if(++f->ref == 1)
pageunchain(f);