diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-08-11 17:56:06 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-08-11 17:56:06 +0200 |
commit | 8c4bb53bdcae806bb13dbe26df51a848ff563d36 (patch) | |
tree | cc1b7c153a5e773b27daa0048cb143aea995468e /sys/src/cmd/hjfs | |
parent | f43df64325efb80fc48a85009df016477238b21b (diff) |
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.
Diffstat (limited to 'sys/src/cmd/hjfs')
-rw-r--r-- | sys/src/cmd/hjfs/buf.c | 57 |
1 files changed, 27 insertions, 30 deletions
diff --git a/sys/src/cmd/hjfs/buf.c b/sys/src/cmd/hjfs/buf.c index cbb962f28..e52c250eb 100644 --- a/sys/src/cmd/hjfs/buf.c +++ b/sys/src/cmd/hjfs/buf.c @@ -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) @@ -109,6 +118,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) { BufReq *r; @@ -122,31 +144,6 @@ undelayreq(Buf *b, BufReq **first, BufReq **last) } 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) { if(b->op & BWRIM){ |