-
David Vorick authored
See if you can spot the mistake: func (h *Host) lockStorageObligation(soid types.FileContractID) { // Check if a lock has been created for this storage obligation. If not, // create one. The map must be accessed under lock, but the request for the // storage lock must not be made under lock. tl, exists := h.lockedStorageObligations[soid] if !exists { tl = new(sync.TryMutex) h.lockedStorageObligations[soid] = tl } tl.Lock() } The mistake is that the storage obligation lock, 'tl.Lock()', can be held for a long time. Per convention, 'lockStorageObligation' must be called under a host lock as it is not an exported function, and has no concurrency prefix. If the storage obligation lock is being held for a long time, so is the host lock. The host lock is critical to the functioning of the host, and should only ever be held briefly. This commit fixes up the locking usage around the storage obligation locks, fixing several critical deadlocks in the host.
8883bca8David Vorick authoredSee if you can spot the mistake: func (h *Host) lockStorageObligation(soid types.FileContractID) { // Check if a lock has been created for this storage obligation. If not, // create one. The map must be accessed under lock, but the request for the // storage lock must not be made under lock. tl, exists := h.lockedStorageObligations[soid] if !exists { tl = new(sync.TryMutex) h.lockedStorageObligations[soid] = tl } tl.Lock() } The mistake is that the storage obligation lock, 'tl.Lock()', can be held for a long time. Per convention, 'lockStorageObligation' must be called under a host lock as it is not an exported function, and has no concurrency prefix. If the storage obligation lock is being held for a long time, so is the host lock. The host lock is critical to the functioning of the host, and should only ever be held briefly. This commit fixes up the locking usage around the storage obligation locks, fixing several critical deadlocks in the host.
Loading