mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-25 17:51:17 +02:00
htlcswitch: fix possible deadlock bug in packetQueue
This commit fixes a possible deadlock within the packetQueue that could be caused by the following circular waiting dependency: packetCoordinator woken up, grabs lock, queue isn’t empty, attempts to send packet to link (lock still held) -> channelLink has commitment overflow, attempts to add new item to packet queue, in AddPkt grabs Lock -> circular wait. We avoid this scenario by *not* holding the lock within the packetCoordinator when we attempt to send a new packet to the switch. Instead, we release the lock before the second select statement in the main processing loop.
This commit is contained in:
@@ -107,12 +107,15 @@ func (p *packetQueue) packetCoordinator() {
|
|||||||
|
|
||||||
nextPkt := p.queue[0]
|
nextPkt := p.queue[0]
|
||||||
|
|
||||||
|
p.queueCond.L.Unlock()
|
||||||
|
|
||||||
// If there aren't any further messages to sent (or the link
|
// If there aren't any further messages to sent (or the link
|
||||||
// didn't immediately read our message), then we'll block and
|
// didn't immediately read our message), then we'll block and
|
||||||
// wait for a new message to be sent into the overflow queue,
|
// wait for a new message to be sent into the overflow queue,
|
||||||
// or for the link's htlcForwarder to wake up.
|
// or for the link's htlcForwarder to wake up.
|
||||||
select {
|
select {
|
||||||
case <-p.freeSlots:
|
case <-p.freeSlots:
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case p.outgoingPkts <- nextPkt:
|
case p.outgoingPkts <- nextPkt:
|
||||||
// Pop the item off the front of the queue and
|
// Pop the item off the front of the queue and
|
||||||
@@ -120,22 +123,20 @@ func (p *packetQueue) packetCoordinator() {
|
|||||||
// the head pointer. This will set us up for
|
// the head pointer. This will set us up for
|
||||||
// the next iteration. If the queue is empty
|
// the next iteration. If the queue is empty
|
||||||
// at this point, then we'll block at the top.
|
// at this point, then we'll block at the top.
|
||||||
|
p.queueCond.L.Lock()
|
||||||
p.queue[0] = nil
|
p.queue[0] = nil
|
||||||
p.queue = p.queue[1:]
|
p.queue = p.queue[1:]
|
||||||
|
p.queueCond.L.Unlock()
|
||||||
atomic.AddInt32(&p.queueLen, -1)
|
atomic.AddInt32(&p.queueLen, -1)
|
||||||
case <-p.quit:
|
case <-p.quit:
|
||||||
p.queueCond.L.Unlock()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-p.quit:
|
case <-p.quit:
|
||||||
p.queueCond.L.Unlock()
|
|
||||||
return
|
return
|
||||||
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
p.queueCond.L.Unlock()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user