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.
This commit is contained in:
cinap_lenrek 2015-08-11 17:56:06 +02:00
parent f43df64325
commit 8c4bb53bdc

View file

@ -81,11 +81,24 @@ givebuf(BufReq req, Buf *b)
{ {
Buf *c, *l; Buf *c, *l;
markbusy(b); assert(!b->busy);
if(req.d == b->d && req.off == b->off){ if(req.d == b->d && req.off == b->off){
markbusy(b);
send(req.resp, &b); send(req.resp, &b);
return; 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){ if(b->op & BDELWRI){
b->op &= ~BDELWRI; b->op &= ~BDELWRI;
b->op |= BWRITE; b->op |= BWRITE;
@ -94,10 +107,6 @@ givebuf(BufReq req, Buf *b)
work(b->d, b); work(b->d, b);
return; 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); changedev(b, req.d, req.off);
b->op &= ~(BWRITE|BDELWRI|BWRIM); b->op &= ~(BWRITE|BDELWRI|BWRIM);
if(req.nodata) if(req.nodata)
@ -108,6 +117,19 @@ givebuf(BufReq req, Buf *b)
} }
} }
static void
handleget(BufReq req)
{
Buf *b;
b = bfree.fnext;
if(b == &bfree){
delayreq(req, &freereq, &freereqlast);
return;
}
givebuf(req, b);
}
static void static void
undelayreq(Buf *b, BufReq **first, BufReq **last) undelayreq(Buf *b, BufReq **first, BufReq **last)
{ {
@ -121,31 +143,6 @@ undelayreq(Buf *b, BufReq **first, BufReq **last)
free(r); 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 static void
handleput(Buf *b) handleput(Buf *b)
{ {