From ae4cc94a9d6cf53e073b9635c72253871a7617c9 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Tue, 8 Nov 2016 06:38:50 +0000 Subject: [PATCH] lib/model: Fix locking order in Availability() (fixes #3634) GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3714 --- lib/model/model.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/model/model.go b/lib/model/model.go index dfb43754a..c8ab9dd22 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -2070,15 +2070,18 @@ func (m *Model) GlobalDirectoryTree(folder, prefix string, levels int, dirsonly } func (m *Model) Availability(folder, file string, version protocol.Vector, block protocol.BlockInfo) []Availability { - // Acquire this lock first, as the value returned from foldersFiles can - // get heavily modified on Close() + // The slightly unusual locking sequence here is because we need to hold + // pmut for the duration (as the value returned from foldersFiles can + // get heavily modified on Close()), but also must acquire fmut before + // pmut. (The locks can be *released* in any order.) + m.fmut.RLock() m.pmut.RLock() defer m.pmut.RUnlock() - m.fmut.RLock() fs, ok := m.folderFiles[folder] devices := m.folderDevices[folder] m.fmut.RUnlock() + if !ok { return nil }