shithub: riscv

Download patch

ref: 1b8fb4fec399dd9520db68b0c8e97d21881d639b
parent: fcfa74a1cfe16dace0c6a34d0c83e290843a35bd
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jun 8 13:39:40 EDT 2014

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.

--- a/sys/src/9/port/swap.c
+++ b/sys/src/9/port/swap.c
@@ -49,7 +49,7 @@
 	swapimage.notext = 1;
 }
 
-uintptr
+static uintptr
 newswap(void)
 {
 	uchar *look;
@@ -64,7 +64,8 @@
 	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 @@
 	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);
@@ -338,12 +341,6 @@
 		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
 		 *  rather than one partially written to the disk
@@ -396,23 +393,27 @@
 		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);
 
-		n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);
-		if(n != BY2PG)
-			nexterror();
+			if(waserror())
+				panic("executeio: page out I/O error");
 
-		kunmap(k);
-		poperror();
+			n = devtab[c->type]->write(c, kaddr, BY2PG, out->daddr);
+			if(n != BY2PG)
+				nexterror();
 
+			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;