git: 9front

Download patch

ref: 50750b43f50b2a70aa61e36e38c0339613bff915
parent: 8b220ec643c364d751d90644d8a45ee135276aff
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Aug 13 06:41:12 EDT 2015

hjfs: fix deadlocks

buffers which still have requests queued on them are not free!

we cannot chanedev() a buffer while it has still requests queued on it
and we canot just queue our request (having different address) on the
buffer while there are other requests before it, otherwise we would
create artificial block dependency that can cause deadlock.

--- a/sys/src/cmd/hjfs/buf.c
+++ b/sys/src/cmd/hjfs/buf.c
@@ -54,16 +54,28 @@
 	BufReq *r;
 
 	r = emalloc(sizeof(*r));
-	memcpy(r, &req, sizeof(*r));
+	*r = req;
 	r->next = nil;
 	if(*first == nil)
-		*first = *last = r;
-	else{
+		*first = r;
+	else
 		(*last)->next = r;
-		*last = r;
-	}
+	*last = r;
 }
 
+static BufReq
+undelayreq(BufReq **first, BufReq **last)
+{
+	BufReq r;
+	
+	r = **first;
+	free(*first);
+	*first = r.next;
+	if(r.next == nil)
+		*last = nil;
+	return r;
+}
+
 static void
 work(Dev *d, Buf *b)
 {
@@ -81,7 +93,7 @@
 {
 	Buf *c, *l;
 
-	assert(!b->busy);
+again:
 	if(req.d == b->d && req.off == b->off){
 		markbusy(b);
 		send(req.resp, &b);
@@ -90,19 +102,30 @@
 	l = &req.d->buf[req.off & BUFHASH];
 	for(c = l->dnext; c != l; c = c->dnext)
 		if(c->off == req.off){
-			if(c->busy){
+			if(c->busy)
 				delayreq(req, &c->next, &c->last);
-				return;
+			else{
+				markbusy(c);
+				send(req.resp, &c);
 			}
-			markbusy(c);
-			send(req.resp, &c);
-			return;
+			if(b->next == nil)
+				return;
+			req = undelayreq(&b->next, &b->last);
+			goto again;
 		}
+	if(b->next != nil){
+		givebuf(undelayreq(&b->next, &b->last), b);
+		b = bfree.fnext;
+	}
+	if(b == &bfree){
+		delayreq(req, &freereq, &freereqlast);
+		return;
+	}
 	markbusy(b);
-	if(b->op & BDELWRI){
+	if(b->d != nil && b->op & BDELWRI){
+		delayreq(req, &b->next, &b->last);
 		b->op &= ~BDELWRI;
 		b->op |= BWRITE;
-		delayreq(req, &b->next, &b->last);
 		b->resp = putb;
 		work(b->d, b);
 		return;
@@ -120,30 +143,10 @@
 static void
 handleget(BufReq req)
 {
-	Buf *b;
-	
-	b = bfree.fnext;
-	if(b == &bfree){
-		delayreq(req, &freereq, &freereqlast);
-		return;
-	}
-	givebuf(req, b);
+	givebuf(req, bfree.fnext);
 }
 
 static void
-undelayreq(Buf *b, BufReq **first, BufReq **last)
-{
-	BufReq *r;
-	
-	r = *first;
-	*first = r->next;
-	if(*last == r)
-		*last = nil;
-	givebuf(*r, b);
-	free(r);
-}
-
-static void
 handleput(Buf *b)
 {
 	if(b->op & BWRIM){
@@ -161,9 +164,9 @@
 	b->op &= ~BWRITE;
 	markfree(b);
 	if(b->next != nil)
-		undelayreq(b, &b->next, &b->last);
+		givebuf(undelayreq(&b->next, &b->last), b);
 	else if(freereq != nil)
-		undelayreq(b, &freereq, &freereqlast);
+		givebuf(undelayreq(&freereq, &freereqlast), b);
 }
 
 static void
--