From 1b8fb4fec399dd9520db68b0c8e97d21881d639b Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sun, 8 Jun 2014 17:39:40 +0200 Subject: swap: make sure swap address sticks arround until page is written to swap we have to make sure the *swap address* doesnt go away, after putting the swap address in the segment pte. after we unlock the segment, the process could be killed or fault which would cause the swap address to be freed *before* we write the page to disk when it pulls the page from the cache and putswap() swap pte. keeping a reference to the page is no good. we have to hold on the swap address. this also has the advantage that we can now test if the swap address is still referenced and can avoid writing to disk. --- sys/src/9/port/swap.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/sys/src/9/port/swap.c b/sys/src/9/port/swap.c index b8e0631ff..c51417520 100644 --- a/sys/src/9/port/swap.c +++ b/sys/src/9/port/swap.c @@ -49,7 +49,7 @@ swapinit(void) swapimage.notext = 1; } -uintptr +static uintptr newswap(void) { uchar *look; @@ -64,7 +64,8 @@ newswap(void) if(look == 0) panic("inconsistent swap"); - *look = 1; + *look = 2; /* ref for pte + io transaction */ + swapalloc.last = look; swapalloc.free--; unlock(&swapalloc); @@ -324,12 +325,14 @@ pagepte(int type, Page **pg) case SG_STACK: case SG_SHARED: /* - * get a new swap address and clear any pages - * referring to it from the cache + * get a new swap address with swapcount 2, one for the pte + * and one extra ref for us while we write the page to disk */ daddr = newswap(); if(daddr == ~0) break; + + /* clear any pages referring to it from the cache */ cachedel(&swapimage, daddr); lock(outp); @@ -337,12 +340,6 @@ pagepte(int type, Page **pg) /* forget anything that it used to cache */ uncachepage(outp); - /* - * 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 @@ -396,23 +393,27 @@ executeio(void) if(ioptr > conf.nswppo) panic("executeio: ioptr %d > %d", ioptr, conf.nswppo); out = iolist[i]; - k = kmap(out); - kaddr = (char*)VA(k); - if(waserror()) - panic("executeio: page out I/O error"); + /* only write when swap address still referenced */ + if(swapcount(out->daddr) > 1){ + k = kmap(out); + kaddr = (char*)VA(k); + + if(waserror()) + panic("executeio: page out I/O error"); - n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr); - if(n != BY2PG) - nexterror(); + n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr); + if(n != BY2PG) + nexterror(); + + kunmap(k); + poperror(); + } - kunmap(k); - poperror(); + /* drop our extra swap reference */ + putswap((Page*)out->daddr); /* Free up the page after I/O */ - lock(out); - out->ref--; - unlock(out); putpage(out); } ioptr = 0; -- cgit v1.2.3