core: Make shutdownDoneCh atomic (#18358)

When issuing a core.Shutdown(), it is common to background the shutdown
request. This allows Vault to continue cleaning up, mainly to release
the stateLock. This allows the shutdown to complete, but is inherently
racy, so the core.shutdownDoneCh needs to be made atomic.
This commit is contained in:
Mike Palmiotto 2022-12-14 10:59:11 -05:00 committed by GitHub
parent 55b21f2012
commit 809a04c8b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -311,8 +311,11 @@ type Core struct {
keepHALockOnStepDown *uint32 keepHALockOnStepDown *uint32
heldHALock physical.Lock heldHALock physical.Lock
// shutdownDoneCh is used to notify when Shutdown() completes // shutdownDoneCh is used to notify when core.Shutdown() completes.
shutdownDoneCh chan struct{} // core.Shutdown() is typically issued in a goroutine to allow Vault to
// release the stateLock. This channel is marked atomic to prevent race
// conditions.
shutdownDoneCh *atomic.Value
// unlockInfo has the keys provided to Unseal until the threshold number of parts is available, as well as the operation nonce // unlockInfo has the keys provided to Unseal until the threshold number of parts is available, as well as the operation nonce
unlockInfo *unlockInformation unlockInfo *unlockInformation
@ -900,7 +903,7 @@ func CreateCore(conf *CoreConfig) (*Core, error) {
clusterPeerClusterAddrsCache: cache.New(3*clusterHeartbeatInterval, time.Second), clusterPeerClusterAddrsCache: cache.New(3*clusterHeartbeatInterval, time.Second),
enableMlock: !conf.DisableMlock, enableMlock: !conf.DisableMlock,
rawEnabled: conf.EnableRaw, rawEnabled: conf.EnableRaw,
shutdownDoneCh: make(chan struct{}), shutdownDoneCh: new(atomic.Value),
replicationState: new(uint32), replicationState: new(uint32),
atomicPrimaryClusterAddrs: new(atomic.Value), atomicPrimaryClusterAddrs: new(atomic.Value),
atomicPrimaryFailoverAddrs: new(atomic.Value), atomicPrimaryFailoverAddrs: new(atomic.Value),
@ -942,6 +945,8 @@ func CreateCore(conf *CoreConfig) (*Core, error) {
atomic.StoreUint32(c.sealed, 1) atomic.StoreUint32(c.sealed, 1)
c.metricSink.SetGaugeWithLabels([]string{"core", "unsealed"}, 0, nil) c.metricSink.SetGaugeWithLabels([]string{"core", "unsealed"}, 0, nil)
c.shutdownDoneCh.Store(make(chan struct{}))
c.allLoggers = append(c.allLoggers, c.logger) c.allLoggers = append(c.allLoggers, c.logger)
c.router.logger = c.logger.Named("router") c.router.logger = c.logger.Named("router")
@ -1239,9 +1244,11 @@ func (c *Core) Shutdown() error {
c.stateLock.Lock() c.stateLock.Lock()
defer c.stateLock.Unlock() defer c.stateLock.Unlock()
if c.shutdownDoneCh != nil {
close(c.shutdownDoneCh) doneCh := c.shutdownDoneCh.Load().(chan struct{})
c.shutdownDoneCh = nil if doneCh != nil {
close(doneCh)
c.shutdownDoneCh.Store((chan struct{})(nil))
} }
return err return err
@ -1258,7 +1265,7 @@ func (c *Core) ShutdownWait() error {
// ShutdownDone returns a channel that will be closed after Shutdown completes // ShutdownDone returns a channel that will be closed after Shutdown completes
func (c *Core) ShutdownDone() <-chan struct{} { func (c *Core) ShutdownDone() <-chan struct{} {
return c.shutdownDoneCh return c.shutdownDoneCh.Load().(chan struct{})
} }
// CORSConfig returns the current CORS configuration // CORSConfig returns the current CORS configuration