summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJonathan Nobels <jonathan@tailscale.com>2026-04-10 13:00:34 -0400
committerJonathan Nobels <jonathan@tailscale.com>2026-04-16 09:51:12 -0400
commitc18f8516c4d7f6339ea586c3f90d1025c9335bcd (patch)
tree5d5ef11dc43fb828911a0dd8fa6faa28cb590ef3
parent399f0483321ac36d9e536cf12907c5ee42fe3ef9 (diff)
downloadtailscale-jonathan/deadlock-fix.tar.xz
tailscale-jonathan/deadlock-fix.zip
ipn/ipnlocal: fix deadlock in ipn bus watcherjonathan/deadlock-fix
fixes tailscale/corp#40401 From an internal stack trace. We witnessed a slow bus error and a complete lock up of the ipn bus watcher. Stack showed a b.mu->t.mu and t.mu->b.mu lock ordering issue when setting up the HealthTracker's initial state and its timer simultaneously fires. Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
-rw-r--r--ipn/ipnlocal/local.go7
1 files changed, 4 insertions, 3 deletions
diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go
index 610d1d7b5..9aa7dc899 100644
--- a/ipn/ipnlocal/local.go
+++ b/ipn/ipnlocal/local.go
@@ -3233,9 +3233,6 @@ func (b *LocalBackend) WatchNotificationsAs(ctx context.Context, actor ipnauth.A
if mask&ipn.NotifyInitialDriveShares != 0 && b.DriveSharingEnabled() {
ini.DriveShares = b.pm.prefs.DriveShares()
}
- if mask&ipn.NotifyInitialHealthState != 0 {
- ini.Health = b.HealthTracker().CurrentState()
- }
if mask&ipn.NotifyInitialSuggestedExitNode != 0 {
if en, err := b.suggestExitNodeLocked(); err == nil {
ini.SuggestedExitNode = &en.ID
@@ -3261,6 +3258,10 @@ func (b *LocalBackend) WatchNotificationsAs(ctx context.Context, actor ipnauth.A
mak.Set(&b.notifyWatchers, sessionID, session)
b.mu.Unlock()
+ if mask&ipn.NotifyInitialHealthState != 0 && ini != nil {
+ ini.Health = b.HealthTracker().CurrentState()
+ }
+
metricCurrentWatchIPNBus.Add(1)
defer metricCurrentWatchIPNBus.Add(-1)