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:
parent
f43df64325
commit
8c4bb53bdc
1 changed files with 27 additions and 30 deletions
|
@ -81,11 +81,24 @@ givebuf(BufReq req, Buf *b)
|
|||
{
|
||||
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 @@ givebuf(BufReq req, Buf *b)
|
|||
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)
|
||||
|
@ -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
|
||||
undelayreq(Buf *b, BufReq **first, BufReq **last)
|
||||
{
|
||||
|
@ -121,31 +143,6 @@ undelayreq(Buf *b, BufReq **first, BufReq **last)
|
|||
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
|
||||
handleput(Buf *b)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue