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;
|
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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue