code: mafs

Download patch

ref: 8db68ca3d6ed8120aef097e365b88e545c4cce6c
parent: 807264bdf7762d6450fd820a1815d90e1ccf357d
author: 9ferno <gophone2015@gmail.com>
date: Wed Oct 26 12:28:43 EDT 2022

attempt to fix the deadlock between putwrite() and dowrite()

--- a/9p.c
+++ b/9p.c
@@ -1303,7 +1303,6 @@
 		if(buf == nil)
 			return -1;
 
-
 		howmuch = min(Blocksize-lastblksize, wbufsize);
 		if(chatty9p > 1)
 		dprint("fill lastblksize %llud howmuch %llud\n",
--- a/all.h
+++ b/all.h
@@ -76,7 +76,7 @@
 		u8	*xiobuf;	/* "real" buffer pointer */
 		Content *io;	/* cast'able to contents */
 	};
-	u32	dirties;	/* number of dirty blocks yet to be written by the writer */
+	u64	dirties;	/* number of dirty blocks yet to be written by the writer */
 	u8 tofree;		/* free this Iobuf after the dirty blocks are written to the disk */
 };
 
--- a/writer.c
+++ b/writer.c
@@ -92,13 +92,14 @@
 		have wlock()'ed the Iobuf too */
 	if(drts.head != nil){
 		b = pluck(drts.head);
-		rwakeup(&drts.isfull);
+		if(drts.n == npendingwrites-1)
+			rwakeup(&drts.isfull);
+		if(chatty9p > 4 && b!=nil){
+			dprint("getwrite done b->blkno %llud\n", b->blkno);
+		stats();
+		}
 	}else
 		b = nil;
-	if(chatty9p > 4 && b!=nil){
-		dprint("getwrite done b->blkno %llud\n", b->blkno);
-		stats();
-	}
 	qunlock(&drts.lck);
 	return b;
 }
@@ -109,17 +110,31 @@
 {
 	Wbuf *w;
 
+	/*
+		copying contents to w before.
+		This avoids rsleep'ing while holding a wlock() on the Iobuf.
+		rsleep'ing while holding the wlock() causes a deadlock()
+		with dowrite() when it tries to decrement dirties by holding
+		a wlock() on the Iobuf.
+	*/
+	w = emalloc9p(sizeof(Wbuf));
+	w->blkno = b->blkno;
+	w->payload = allocmemunit();
+	memcpy(w->payload, b->xiobuf, Rawblocksize);
+	b->dirties++;
+	w->iobuf = b;
+	if(chkwunlock(b) == 0){
+		showbuf(b);
+		panic("putwrite chkwunlock(p) == 0 called by %#p\n", getcallerpc(&b));
+	}
+
 	qlock(&drts.lck);
 	if(chatty9p > 4){
 		dprint("putwrite start p->blkno %llud\n", b->blkno);
 		stats();
 	}
-	if(drts.n > npendingwrites)
+	if(drts.n == npendingwrites)
 		rsleep(&drts.isfull);
-	w = emalloc9p(sizeof(Wbuf));
-	w->blkno = b->blkno;
-	w->payload = allocmemunit();
-	memcpy(w->payload, b->xiobuf, Rawblocksize);
 	if(drts.head == nil){
 		drts.head = drts.tail = w;
 	}else{
@@ -130,12 +145,6 @@
 	drts.n++;
 	if(drts.n == 1)
 		rwakeup(&drts.isempty);
-	b->dirties++;
-	w->iobuf = b;
-	if(chkwunlock(b) == 0){
-		showbuf(b);
-		panic("putwrite chkwunlock(p) == 0 called by %#p\n", getcallerpc(&b));
-	}
 	if(chatty9p > 4 && b!=nil){
 		dprint("putwrite done b->blkno %llud\n", b->blkno);
 		stats();