diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-08-13 10:41:12 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2015-08-13 10:41:12 +0200 |
commit | 592b8d5b3528ba34f5bd0fffebdffcac1c9450cd (patch) | |
tree | 9045bc65692f57bbf7866cc8a92acc0d103ca6c9 /sys/src | |
parent | 8c4bb53bdcae806bb13dbe26df51a848ff563d36 (diff) |
hjfs: fix deadlocks
buffers which still have requests queued on them are not free!
we cannot chanedev() a buffer while it has still requests queued on it
and we canot just queue our request (having different address) on the
buffer while there are other requests before it, otherwise we would
create artificial block dependency that can cause deadlock.
Diffstat (limited to 'sys/src')
-rw-r--r-- | sys/src/cmd/hjfs/buf.c | 75 |
1 files changed, 39 insertions, 36 deletions
diff --git a/sys/src/cmd/hjfs/buf.c b/sys/src/cmd/hjfs/buf.c index e52c250eb..1850bf6db 100644 --- a/sys/src/cmd/hjfs/buf.c +++ b/sys/src/cmd/hjfs/buf.c @@ -54,14 +54,26 @@ delayreq(BufReq req, BufReq **first, BufReq **last) BufReq *r; r = emalloc(sizeof(*r)); - memcpy(r, &req, sizeof(*r)); + *r = req; r->next = nil; if(*first == nil) - *first = *last = r; - else{ + *first = r; + else (*last)->next = r; - *last = r; - } + *last = r; +} + +static BufReq +undelayreq(BufReq **first, BufReq **last) +{ + BufReq r; + + r = **first; + free(*first); + *first = r.next; + if(r.next == nil) + *last = nil; + return r; } static void @@ -81,7 +93,7 @@ givebuf(BufReq req, Buf *b) { Buf *c, *l; - assert(!b->busy); +again: if(req.d == b->d && req.off == b->off){ markbusy(b); send(req.resp, &b); @@ -90,19 +102,30 @@ givebuf(BufReq req, Buf *b) l = &req.d->buf[req.off & BUFHASH]; for(c = l->dnext; c != l; c = c->dnext) if(c->off == req.off){ - if(c->busy){ + if(c->busy) delayreq(req, &c->next, &c->last); - return; + else{ + markbusy(c); + send(req.resp, &c); } - markbusy(c); - send(req.resp, &c); - return; + if(b->next == nil) + return; + req = undelayreq(&b->next, &b->last); + goto again; } + if(b->next != nil){ + givebuf(undelayreq(&b->next, &b->last), b); + b = bfree.fnext; + } + if(b == &bfree){ + delayreq(req, &freereq, &freereqlast); + return; + } markbusy(b); - if(b->op & BDELWRI){ + if(b->d != nil && b->op & BDELWRI){ + delayreq(req, &b->next, &b->last); b->op &= ~BDELWRI; b->op |= BWRITE; - delayreq(req, &b->next, &b->last); b->resp = putb; work(b->d, b); return; @@ -120,27 +143,7 @@ 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; - - r = *first; - *first = r->next; - if(*last == r) - *last = nil; - givebuf(*r, b); - free(r); + givebuf(req, bfree.fnext); } static void @@ -161,9 +164,9 @@ handleput(Buf *b) b->op &= ~BWRITE; markfree(b); if(b->next != nil) - undelayreq(b, &b->next, &b->last); + givebuf(undelayreq(&b->next, &b->last), b); else if(freereq != nil) - undelayreq(b, &freereq, &freereqlast); + givebuf(undelayreq(&freereq, &freereqlast), b); } static void |