M port/devproc.c => port/devproc.c +2 -0
@@ 975,6 975,7 @@ txt2data(Proc *p, Segment *s)
ps->flen = s->flen;
ps->flushme = 1;
+ qlock(&p->seglock);
for(i = 0; i < NSEG; i++)
if(p->seg[i] == s)
break;
@@ 985,6 986,7 @@ txt2data(Proc *p, Segment *s)
putseg(s);
qlock(&ps->lk);
p->seg[i] = ps;
+ qunlock(&p->seglock);
return ps;
}
M port/fault.c => port/fault.c +34 -13
@@ 51,6 51,7 @@ int
fixfault(Segment *s, ulong addr, int read, int doputmmu)
{
int type;
+ int ref;
Pte **p, *etp;
char buf[ERRLEN];
ulong va, mmuphys=0, soff;
@@ 92,6 93,11 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
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);
unlock(lkp);
@@ 129,7 135,11 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
lkp = *pg;
lock(lkp);
- if(lkp->ref > 1) {
+ if(lkp->image == &swapimage && lkp->daddr)
+ ref = lkp->ref + swapcount(lkp->daddr);
+ else
+ ref = lkp->ref;
+ if(ref > 1) {
unlock(lkp);
new = newpage(0, &s, addr);
if(s == 0)
@@ 139,7 149,8 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
putpage(lkp);
}
else {
- /* put a duplicate of a text page back onto
+ /* 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)
@@ 181,7 192,7 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
void
pio(Segment *s, ulong addr, ulong soff, Page **p)
{
- Page *new;
+ Page *new, *new2;
KMap *k;
Chan *c;
int n, ask;
@@ 197,7 208,7 @@ pio(Segment *s, ulong addr, ulong soff, Page **p)
else {
daddr = swapaddr(loadrec);
new = lookpage(&swapimage, daddr);
- if(new)
+ if(new != nil)
putswap(loadrec);
}
@@ 235,7 246,8 @@ pio(Segment *s, ulong addr, ulong soff, Page **p)
poperror();
kunmap(k);
qlock(&s->lk);
- if(*p == 0) { /* Someone may have got there first */
+ /* race, we may have multiple simultaneous reads */
+ if(*p == 0) {
new->daddr = daddr;
cachepage(new, s->image);
*p = new;
@@ 245,10 257,21 @@ pio(Segment *s, ulong addr, ulong soff, Page **p)
}
else { /* This is paged out */
c = swapimage.c;
+ qlock(&swapimage.rdlock); /* mutex */
+
+ new2 = lookpage(&swapimage, daddr);
+ if(new2 != nil){
+ putpage(new);
+ putswap(*p);
+ *p = new2;
+ qunlock(&swapimage.rdlock);
+ return;
+ }
if(waserror()) {
kunmap(k);
putpage(new);
+ qunlock(&swapimage.rdlock);
qlock(&s->lk);
qunlock(&s->lk);
faulterror("sys: page in I/O error");
@@ 262,14 285,12 @@ pio(Segment *s, ulong addr, ulong soff, Page **p)
kunmap(k);
qlock(&s->lk);
- if(pagedout(*p)) {
- new->daddr = daddr;
- cachepage(new, &swapimage);
- putswap(*p);
- *p = new;
- }
- else
- putpage(new);
+ new->daddr = daddr;
+ putswap(*p);
+ cachepage(new, &swapimage);
+ *p = new;
+
+ qunlock(&swapimage.rdlock);
}
if(s->flushme)
M port/page.c => port/page.c +11 -2
@@ 270,10 270,16 @@ retry:
if(retries++ > 10000)
panic("duppage %d", retries);
- /* No dup for swap/cache pages */
- if(p->ref == 0 || p->image == nil || p->image->notext)
+ /* don't dup pages with no image */
+ if(p->ref == 0 || p->image == nil)
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).
@@ 390,6 396,9 @@ cachedel(Image *i, ulong 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;
break;
}
l = &f->hash;
M port/portdat.h => port/portdat.h +2 -0
@@ 326,6 326,7 @@ struct Image
Image *hash; /* Qid hash chains */
Image *next; /* Free list */
int notext; /* no file associated */
+ QLock rdlock; /* mutex for reading from image */
};
struct Pte
@@ 543,6 544,7 @@ struct Proc
int state;
char *psstate; /* What /proc/#/status reports */
Segment *seg[NSEG];
+ QLock seglock; /* locked whenever seg[] changes */
ulong pid;
ulong noteid; /* Equivalent of note group */
M port/portfns.h => port/portfns.h +1 -0
@@ 293,6 293,7 @@ int spllo(void);
void splx(int);
void splxpc(int);
void srvrecover(Chan*, Chan*);
+int swapcount(ulong);
void swapinit(void);
Block* trimblock(Block*, int, int);
void tsleep(Rendez*, int (*)(void*), void*, int);
M port/proc.c => port/proc.c +2 -0
@@ 796,6 796,7 @@ pexit(char *exitstr, int freemem)
if(!freemem)
addbroken(up);
+ qlock(&up->seglock);
es = &up->seg[NSEG];
for(s = up->seg; s < es; s++) {
if(*s) {
@@ 803,6 804,7 @@ pexit(char *exitstr, int freemem)
*s = 0;
}
}
+ qunlock(&up->seglock);
lock(&up->exl); /* Prevent my children from leaving waits */
up->pid = 0;
M port/swap.c => port/swap.c +36 -8
@@ 60,6 60,8 @@ 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;
@@ 71,10 73,18 @@ void
dupswap(Page *p)
{
lock(&swapalloc);
+ if(swapalloc.swmap[((ulong)p)/BY2PG]==255)
+ panic("dupswap");
swapalloc.swmap[((ulong)p)/BY2PG]++;
unlock(&swapalloc);
}
+int
+swapcount(ulong daddr)
+{
+ return swapalloc.swmap[daddr/BY2PG];
+}
+
void
kickpager(void)
{
@@ 106,17 116,21 @@ loop:
sleep(&swapalloc.r, needpages, 0);
while(needpages(junk)) {
- p++;
- if(p >= ep)
- p = proctab(0);
-
- if(p->state == Dead || p->kp)
- continue;
if(swapimage.c) {
+ p++;
+ if(p >= ep)
+ p = proctab(0);
+
+ if(p->state == Dead || p->kp)
+ continue;
+
+ qlock(&p->seglock);
for(i = 0; i < NSEG; i++) {
- if(!needpages(junk))
+ if(!needpages(junk)){
+ qunlock(&p->seglock);
goto loop;
+ }
if(s = p->seg[i]) {
switch(s->type&SG_TYPE) {
@@ 141,6 155,7 @@ loop:
}
}
}
+ qunlock(&p->seglock);
}
else {
if(!cpuserver)
@@ 264,12 279,24 @@ pagepte(int type, Page **pg)
case SG_SHARED:
case SG_SHDATA:
case SG_MAP:
+ /* if it's already on disk, we're done */
+#ifdef asdf
+ lock(outp);
+ if(outp->daddr != 0 && outp->image == &swapimage){
+ dupswap((Page*)outp->daddr);
+ *pg = (Page*)(outp->daddr|PG_ONSWAP);
+ unlock(outp);
+ putpage(outp);
+ return;
+ }
+ unlock(outp);
+#endif asdf
+
daddr = newswap();
cachedel(&swapimage, daddr);
lock(outp);
outp->ref++;
uncachepage(outp);
- unlock(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
@@ 278,6 305,7 @@ pagepte(int type, Page **pg)
outp->daddr = daddr;
cachepage(outp, &swapimage);
*pg = (Page*)(daddr|PG_ONSWAP);
+ unlock(outp);
/* Add me to IO transaction list */
iolist[ioptr++] = outp;
M port/sysproc.c => port/sysproc.c +22 -0
@@ 92,9 92,16 @@ sysrfork(ulong *arg)
/* Make a new set of memory segments */
n = flag & RFMEM;
+ qlock(&p->seglock);
+ if(waserror()){
+ qunlock(&p->seglock);
+ nexterror();
+ }
for(i = 0; i < NSEG; i++)
if(up->seg[i])
p->seg[i] = dupseg(up->seg, i, n);
+ qunlock(&p->seglock);
+ poperror();
/* File descriptors */
if(flag & (RFFDG|RFCFDG)) {
@@ 304,6 311,11 @@ sysexec(ulong *arg)
if(spage > TSTKSIZ)
error(Enovmem);
+ qlock(&up->seglock);
+ if(waserror()){
+ qunlock(&up->seglock);
+ nexterror();
+ }
up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG);
/*
@@ 383,6 395,8 @@ sysexec(ulong *arg)
s = up->seg[ESEG];
up->seg[ESEG] = 0;
up->seg[SSEG] = s;
+ qunlock(&up->seglock);
+ poperror();
s->base = USTKTOP-USTKSIZE;
s->top = USTKTOP;
relocateseg(s, USTKTOP-TSTKTOP);
@@ 587,6 601,12 @@ syssegdetach(ulong *arg)
ulong addr;
Segment *s;
+ qlock(&up->seglock);
+ if(waserror()){
+ qunlock(&up->seglock);
+ nexterror();
+ }
+
s = 0;
addr = arg[0];
for(i = 0; i < NSEG; i++)
@@ 609,6 629,8 @@ found:
up->seg[i] = 0;
qunlock(&s->lk);
putseg(s);
+ qunlock(&up->seglock);
+ poperror();
/* Ensure we flush any entries from the lost segment */
flushmmu();