From ac52599eef2ab79a64c30a8046a51b62501ca9ab Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Fri, 26 Jul 2013 01:51:03 +0200 Subject: ether82563: avoid deadlock due to icansleep() trying to acquire Rbpool.Lock icansleep() violates the lock ordering due to the following cases: rbfree(): ilock(Rbpool.Lock) -> wakeup(): spli(), lock(Rbpool.Rendez) sleep(): splhi(), lock(Rbpool.Rendez) -> icansleep(): ilock(Rbpool.Lock) erik fixed this moving the wakeup() out of the ilock() in rbfree(), but i think it is an error to try acquiering a ilock in sleeps wait condition function in general. so this is what we do: in the icansleep() function, we check for the *real* event we care about; that is, if theres a buffer available in the Rbpool. this is to handle the case when rbfree() makes a buffer available *before* it sees us setting p->starve = 1. p->starve is now just used to gate rbfree() from calling wakeup() as an optimization. this might cause spurious wakeups but they are not a problem. missed wakeups is the thing we have to prevent. --- sys/src/9/pc/ether82563.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'sys/src/9/pc/ether82563.c') diff --git a/sys/src/9/pc/ether82563.c b/sys/src/9/pc/ether82563.c index eb6e35998..f4eab6a0f 100644 --- a/sys/src/9/pc/ether82563.c +++ b/sys/src/9/pc/ether82563.c @@ -792,14 +792,9 @@ static int icansleep(void *v) { Rbpool *p; - int r; p = v; - ilock(p); - r = p->starve == 0; - iunlock(p); - - return r; + return p->b != nil; } static Block* @@ -1058,9 +1053,7 @@ i82563replenish(Ctlr *ctlr, int maysleep) print("i82563%d: no rx buffers\n", ctlr->pool); if(maysleep == 0) return -1; - ilock(p); p->starve = 1; - iunlock(p); sleep(p, icansleep, p); goto redux; } -- cgit v1.2.3