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
1 changed files with 14 additions and 7 deletions

View File

@ -311,8 +311,11 @@ type Core struct {
keepHALockOnStepDown *uint32
heldHALock physical.Lock
// shutdownDoneCh is used to notify when Shutdown() completes
shutdownDoneCh chan struct{}
// shutdownDoneCh is used to notify when core.Shutdown() completes.
// 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 *unlockInformation
@ -900,7 +903,7 @@ func CreateCore(conf *CoreConfig) (*Core, error) {
clusterPeerClusterAddrsCache: cache.New(3*clusterHeartbeatInterval, time.Second),
enableMlock: !conf.DisableMlock,
rawEnabled: conf.EnableRaw,
shutdownDoneCh: make(chan struct{}),
shutdownDoneCh: new(atomic.Value),
replicationState: new(uint32),
atomicPrimaryClusterAddrs: new(atomic.Value),
atomicPrimaryFailoverAddrs: new(atomic.Value),
@ -942,6 +945,8 @@ func CreateCore(conf *CoreConfig) (*Core, error) {
atomic.StoreUint32(c.sealed, 1)
c.metricSink.SetGaugeWithLabels([]string{"core", "unsealed"}, 0, nil)
c.shutdownDoneCh.Store(make(chan struct{}))
c.allLoggers = append(c.allLoggers, c.logger)
c.router.logger = c.logger.Named("router")
@ -1239,9 +1244,11 @@ func (c *Core) Shutdown() error {
c.stateLock.Lock()
defer c.stateLock.Unlock()
if c.shutdownDoneCh != nil {
close(c.shutdownDoneCh)
c.shutdownDoneCh = nil
doneCh := c.shutdownDoneCh.Load().(chan struct{})
if doneCh != nil {
close(doneCh)
c.shutdownDoneCh.Store((chan struct{})(nil))
}
return err
@ -1258,7 +1265,7 @@ func (c *Core) ShutdownWait() error {
// ShutdownDone returns a channel that will be closed after Shutdown completes
func (c *Core) ShutdownDone() <-chan struct{} {
return c.shutdownDoneCh
return c.shutdownDoneCh.Load().(chan struct{})
}
// CORSConfig returns the current CORS configuration