shithub: riscv

Download patch

ref: 592b8d5b3528ba34f5bd0fffebdffcac1c9450cd
parent: 8c4bb53bdcae806bb13dbe26df51a848ff563d36
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