@@ 17,7 17,7 @@ fault(ulong addr, int read)
m->pfault++;
for(;;) {
- s = seg(up, addr, 1);
+ s = seg(up, addr, 1); /* leaves s->lk qlocked if seg != nil */
if(s == 0) {
up->psstate = sps;
return -1;
@@ 88,18 88,21 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
break;
case SG_SHDATA: /* Shared data */
+ shared:
if(pagedout(*pg))
pio(s, addr, soff, pg);
lkp = *pg;
lock(lkp);
- /* uncache the current page (since we may be changing it)
- * and, if a text page, put a duplicate back onto
- * the free list
- */
- if(lkp->image)
- duppage(lkp);
+ /* uncache the current swap image (since we may be changing it) */
+ if(lkp->image){
+ if(lkp->image == &swapimage)
+ uncachepage(lkp);
+ else
+ duppage(lkp);
+ }
+
unlock(lkp);
goto done;
@@ 118,15 121,16 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
*pg = new;
}
- /* NO break */
+ if(type == SG_SHARED)
+ goto shared;
- case SG_DATA: /* Demand load/pagein/copy on write */
+ goto notshared;
+
+ case SG_DATA:
+ notshared: /* Demand load/pagein/copy on write */
if(pagedout(*pg))
pio(s, addr, soff, pg);
- if(type == SG_SHARED)
- goto done;
-
if(read && conf.copymode == 0) {
mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID;
(*pg)->modref |= PG_REF;
@@ 135,7 139,7 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
lkp = *pg;
lock(lkp);
- if(lkp->image == &swapimage && lkp->daddr)
+ if(lkp->image == &swapimage)
ref = lkp->ref + swapcount(lkp->daddr);
else
ref = lkp->ref;
@@ 153,8 157,12 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
* and, if a text page, put a duplicate back onto
* the free list
*/
- if(lkp->image)
- duppage(lkp);
+ if(lkp->image){
+ if(lkp->image == &swapimage)
+ uncachepage(lkp);
+ else
+ duppage(lkp);
+ }
unlock(lkp);
}
@@ 201,18 209,18 @@ pio(Segment *s, ulong addr, ulong soff, Page **p)
Page *loadrec;
loadrec = *p;
- if(loadrec == 0) {
- daddr = s->fstart+soff; /* Compute disc address */
+ if(loadrec == 0) { /* from a text/data image */
+ daddr = s->fstart+soff;
new = lookpage(s->image, daddr);
}
- else {
+ else { /* from a swap image */
daddr = swapaddr(loadrec);
new = lookpage(&swapimage, daddr);
if(new != nil)
putswap(loadrec);
}
- if(new) { /* Page found from cache */
+ if(new != nil) { /* Page found from cache */
*p = new;
return;
}
@@ 259,13 267,27 @@ pio(Segment *s, ulong addr, ulong soff, Page **p)
c = swapimage.c;
qlock(&swapimage.rdlock); /* mutex */
+ /*
+ * multiple processes could be swapping in the
+ * same page for the same segment
+ */
+ if(!pagedout(*p)){
+ putpage(new);
+ qunlock(&swapimage.rdlock);
+ goto done;
+ }
+
+ /*
+ * multiple processes could be swapping in the
+ * same page for different segments
+ */
new2 = lookpage(&swapimage, daddr);
if(new2 != nil){
putpage(new);
- putswap(*p);
*p = new2;
+ putswap(loadrec);
qunlock(&swapimage.rdlock);
- return;
+ goto done;
}
if(waserror()) {
@@ 286,13 308,14 @@ pio(Segment *s, ulong addr, ulong soff, Page **p)
qlock(&s->lk);
new->daddr = daddr;
- putswap(*p);
cachepage(new, &swapimage);
*p = new;
+ putswap(loadrec);
qunlock(&swapimage.rdlock);
}
+done:
if(s->flushme)
memset((*p)->cachectl, PG_TXTFLUSH, sizeof((*p)->cachectl));
}
@@ 215,6 215,10 @@ putpage(Page *p)
lock(&palloc);
lock(p);
+
+ if(p->ref == 0)
+ panic("putpage");
+
if(--p->ref > 0) {
unlock(p);
unlock(&palloc);
@@ 271,15 275,9 @@ retry:
panic("duppage %d", retries);
/* don't dup pages with no image */
- if(p->ref == 0 || p->image == nil)
+ if(p->ref == 0 || p->image == nil || p->image->notext)
return;
- /* No dup for swap/cache pages but we still have to uncache */
- if(p->image->notext){
- uncachepage(p);
- return;
- }
-
/*
* normal lock ordering is to call
* lock(&palloc) before lock(p).
@@ 395,10 393,14 @@ cachedel(Image *i, ulong daddr)
l = &pghash(daddr);
for(f = *l; f; f = f->hash) {
if(f->image == i && f->daddr == daddr) {
- *l = f->hash;
- putimage(f->image);
- f->image = 0;
- f->daddr = 0;
+ lock(f);
+ if(f->image == i && f->daddr == daddr){
+ *l = f->hash;
+ putimage(f->image);
+ f->image = 0;
+ f->daddr = 0;
+ }
+ unlock(f);
break;
}
l = &f->hash;
@@ 60,12 60,12 @@ putswap(Page *p)
lock(&swapalloc);
idx = &swapalloc.swmap[((ulong)p)/BY2PG];
if(--(*idx) == 0) {
- if(swapalloc.swmap[((ulong)p)/BY2PG]==255)
- panic("putswap");
swapalloc.free++;
if(idx < swapalloc.last)
swapalloc.last = idx;
}
+ if(*idx >= 254)
+ panic("putswap %lux == %ud", p, *idx);
unlock(&swapalloc);
}
@@ 73,9 73,8 @@ void
dupswap(Page *p)
{
lock(&swapalloc);
- if(swapalloc.swmap[((ulong)p)/BY2PG]==255)
+ if(++swapalloc.swmap[((ulong)p)/BY2PG] == 0)
panic("dupswap");
- swapalloc.swmap[((ulong)p)/BY2PG]++;
unlock(&swapalloc);
}
@@ 279,10 278,10 @@ pagepte(int type, Page **pg)
case SG_SHARED:
case SG_SHDATA:
case SG_MAP:
- /* if it's already on disk, we're done */
+ /* if it's already on disk, no need to do io again */
#ifdef asdf
lock(outp);
- if(outp->daddr != 0 && outp->image == &swapimage){
+ if(outp->image == &swapimage){
dupswap((Page*)outp->daddr);
*pg = (Page*)(outp->daddr|PG_ONSWAP);
unlock(outp);
@@ 292,22 291,34 @@ pagepte(int type, Page **pg)
unlock(outp);
#endif asdf
+ /*
+ * get a new swap address and clear any pages
+ * referring to it from the cache
+ */
daddr = newswap();
cachedel(&swapimage, daddr);
+
lock(outp);
- outp->ref++;
+
+ /* forget anything that it used to cache */
uncachepage(outp);
- /* Enter swap page into cache before segment is unlocked so that
- * a fault will cause a cache recovery rather than a pagein on a
- * partially written block.
+ /*
+ * incr the reference count to make sure it sticks around while
+ * being written
+ */
+ outp->ref++;
+
+ /*
+ * enter it into the cache so that a fault happening
+ * during the write will grab the page from the cache
*/
outp->daddr = daddr;
cachepage(outp, &swapimage);
*pg = (Page*)(daddr|PG_ONSWAP);
unlock(outp);
- /* Add me to IO transaction list */
+ /* Add page to IO transaction list */
iolist[ioptr++] = outp;
break;
}