ref: 8c4bb53bdcae806bb13dbe26df51a848ff563d36
parent: f43df64325efb80fc48a85009df016477238b21b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Aug 11 13:56:06 EDT 2015
hjfs: fix abort() in givebuf() it is possible for another getbuf() on buffer b to come in before undelayreq() calls givebuf() on a buffer again. then givebuf() would find b already busy and abort(). instead, we now handle what getbuf() did in givebuf() and consider the Buf* argument to givebuf() as a hint only for the case when we have to actually flush/read a block from disk.
--- a/sys/src/cmd/hjfs/buf.c
+++ b/sys/src/cmd/hjfs/buf.c
@@ -81,11 +81,24 @@
{
Buf *c, *l;
- markbusy(b);
+ assert(!b->busy);
if(req.d == b->d && req.off == b->off){
+ markbusy(b);
send(req.resp, &b);
return;
}
+ l = &req.d->buf[req.off & BUFHASH];
+ for(c = l->dnext; c != l; c = c->dnext)
+ if(c->off == req.off){
+ if(c->busy){
+ delayreq(req, &c->next, &c->last);
+ return;
+ }
+ markbusy(c);
+ send(req.resp, &c);
+ return;
+ }
+ markbusy(b);
if(b->op & BDELWRI){
b->op &= ~BDELWRI;
b->op |= BWRITE;
@@ -94,10 +107,6 @@
work(b->d, b);
return;
}
- l = &req.d->buf[req.off & BUFHASH];
- for(c = l->dnext; c != l; c = c->dnext)
- if(c->off == req.off)
- abort();
changedev(b, req.d, req.off);
b->op &= ~(BWRITE|BDELWRI|BWRIM);
if(req.nodata)
@@ -109,6 +118,19 @@
}
static void
+handleget(BufReq req)
+{
+ Buf *b;
+
+ b = bfree.fnext;
+ if(b == &bfree){
+ delayreq(req, &freereq, &freereqlast);
+ return;
+ }
+ givebuf(req, b);
+}
+
+static void
undelayreq(Buf *b, BufReq **first, BufReq **last)
{
BufReq *r;
@@ -119,31 +141,6 @@
*last = nil;
givebuf(*r, b);
free(r);
-}
-
-static void
-handleget(BufReq req)
-{
- Buf *b, *l;
- Dev *d;
-
- d = req.d;
- l = &d->buf[req.off & BUFHASH];
- for(b = l->dnext; b != l; b = b->dnext)
- if(b->off == req.off){
- if(b->busy){
- delayreq(req, &b->next, &b->last);
- return;
- }
- givebuf(req, b);
- return;
- }
- if(bfree.fnext == &bfree){
- delayreq(req, &freereq, &freereqlast);
- return;
- }
- b = bfree.fnext;
- givebuf(req, b);
}
static void