|
@@ -2384,8 +2384,14 @@ func (m *model) scheduleConnectionPromotion() {
|
|
|
// be called after adding new connections, and after closing a primary
|
|
|
// device connection.
|
|
|
func (m *model) promoteConnections() {
|
|
|
+ // Slice of actions to take on connections after releasing the main
|
|
|
+ // mutex. We do this so that we do not perform blocking network actions
|
|
|
+ // inside the loop, and also to avoid a possible deadlock with calling
|
|
|
+ // Start() on connections that are already executing a Close() with a
|
|
|
+ // callback into the model...
|
|
|
+ var postLockActions []func()
|
|
|
+
|
|
|
m.mut.Lock()
|
|
|
- defer m.mut.Unlock()
|
|
|
|
|
|
for deviceID, connIDs := range m.deviceConnIDs {
|
|
|
cm, passwords := m.generateClusterConfigRLocked(deviceID)
|
|
@@ -2398,11 +2404,13 @@ func (m *model) promoteConnections() {
|
|
|
// on where we get ClusterConfigs from the peer.)
|
|
|
conn := m.connections[connIDs[0]]
|
|
|
l.Debugf("Promoting connection to %s at %s", deviceID.Short(), conn)
|
|
|
- if conn.Statistics().StartedAt.IsZero() {
|
|
|
- conn.SetFolderPasswords(passwords)
|
|
|
- conn.Start()
|
|
|
- }
|
|
|
- conn.ClusterConfig(cm)
|
|
|
+ postLockActions = append(postLockActions, func() {
|
|
|
+ if conn.Statistics().StartedAt.IsZero() {
|
|
|
+ conn.SetFolderPasswords(passwords)
|
|
|
+ conn.Start()
|
|
|
+ }
|
|
|
+ conn.ClusterConfig(cm)
|
|
|
+ })
|
|
|
m.promotedConnID[deviceID] = connIDs[0]
|
|
|
}
|
|
|
|
|
@@ -2411,12 +2419,20 @@ func (m *model) promoteConnections() {
|
|
|
for _, connID := range connIDs[1:] {
|
|
|
conn := m.connections[connID]
|
|
|
if conn.Statistics().StartedAt.IsZero() {
|
|
|
- conn.SetFolderPasswords(passwords)
|
|
|
- conn.Start()
|
|
|
- conn.ClusterConfig(&protocol.ClusterConfig{Secondary: true})
|
|
|
+ postLockActions = append(postLockActions, func() {
|
|
|
+ conn.SetFolderPasswords(passwords)
|
|
|
+ conn.Start()
|
|
|
+ conn.ClusterConfig(&protocol.ClusterConfig{Secondary: true})
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ m.mut.Unlock()
|
|
|
+
|
|
|
+ for _, action := range postLockActions {
|
|
|
+ action()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
func (m *model) DownloadProgress(conn protocol.Connection, p *protocol.DownloadProgress) error {
|