From 1a931bedea759298e3e3161194dad3f3cf94171f Mon Sep 17 00:00:00 2001 From: Uri Sternik Date: Sun, 30 Nov 2025 15:36:39 +0200 Subject: [PATCH 1/2] Fix race condition in config-manager when label is unset When the node label (nvidia.com/device-plugin.config) is not set, a race condition could cause the config-manager to hang indefinitely on startup. The issue occurred when the informer's AddFunc fired before the first Get() call, setting current="" and broadcasting. When Get() was subsequently called, it found lastRead == current (both empty strings) and waited forever, as no future events would wake it up. This fix adds an 'initialized' flag to SyncableConfig to ensure the first Get() call never waits, regardless of timing. Subsequent Get() calls still wait properly when the value hasn't changed. Signed-off-by: Uri Sternik --- cmd/config-manager/main.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cmd/config-manager/main.go b/cmd/config-manager/main.go index f95d3332d..4e4058842 100644 --- a/cmd/config-manager/main.go +++ b/cmd/config-manager/main.go @@ -79,10 +79,11 @@ type Flags struct { // Multiple calls to Set() do not queue, meaning that only calls to Get() made // *before* a call to Set() will be notified. type SyncableConfig struct { - cond *sync.Cond - mutex sync.Mutex - current string - lastRead string + cond *sync.Cond + mutex sync.Mutex + current string + lastRead string + initialized bool } // NewSyncableConfig creates a new SyncableConfig @@ -106,9 +107,10 @@ func (m *SyncableConfig) Set(value string) { func (m *SyncableConfig) Get() string { m.mutex.Lock() defer m.mutex.Unlock() - if m.lastRead == m.current { + if m.initialized && m.lastRead == m.current { m.cond.Wait() } + m.initialized = true m.lastRead = m.current return m.lastRead } From 403778c01f8df20b701841abe85b513907cec90c Mon Sep 17 00:00:00 2001 From: Uri Sternik Date: Sun, 7 Dec 2025 10:12:51 +0200 Subject: [PATCH 2/2] CR suggestion Signed-off-by: Uri Sternik --- cmd/config-manager/main.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/cmd/config-manager/main.go b/cmd/config-manager/main.go index 4e4058842..6c21a4b0c 100644 --- a/cmd/config-manager/main.go +++ b/cmd/config-manager/main.go @@ -79,11 +79,10 @@ type Flags struct { // Multiple calls to Set() do not queue, meaning that only calls to Get() made // *before* a call to Set() will be notified. type SyncableConfig struct { - cond *sync.Cond - mutex sync.Mutex - current string - lastRead string - initialized bool + cond *sync.Cond + mutex sync.Mutex + current string + lastRead *string } // NewSyncableConfig creates a new SyncableConfig @@ -107,12 +106,12 @@ func (m *SyncableConfig) Set(value string) { func (m *SyncableConfig) Get() string { m.mutex.Lock() defer m.mutex.Unlock() - if m.initialized && m.lastRead == m.current { + if m.lastRead != nil && *m.lastRead == m.current { m.cond.Wait() } - m.initialized = true - m.lastRead = m.current - return m.lastRead + val := m.current + m.lastRead = &val + return *m.lastRead } func main() {