fix: protect ReplicationStats against concurrent map iteration and write crash (#17403)

This commit is contained in:
Klaus Post 2023-06-12 09:17:11 -07:00 committed by GitHub
parent bb24346e04
commit 6f2406b0b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 7 deletions

View file

@ -373,7 +373,7 @@ func (f *folderScanner) sendUpdate() {
}
if flat := f.updateCache.sizeRecursive(f.newCache.Info.Name); flat != nil {
select {
case f.updates <- *flat:
case f.updates <- flat.clone():
default:
}
f.lastUpdate = time.Now()

View file

@ -88,6 +88,20 @@ func (ats *allTierStats) merge(other *allTierStats) {
}
}
func (ats *allTierStats) clone() *allTierStats {
if ats == nil {
return nil
}
dst := *ats
if dst.Tiers != nil {
dst.Tiers = make(map[string]tierStats, len(dst.Tiers))
for tier, st := range dst.Tiers {
dst.Tiers[tier] = st
}
}
return &dst
}
func (ats *allTierStats) adminStats(stats map[string]madmin.TierStats) map[string]madmin.TierStats {
if ats == nil {
return stats
@ -168,6 +182,25 @@ type replicationAllStatsV1 struct {
ReplicaSize uint64 `msg:"ReplicaSize,omitempty"`
}
// clone creates a deep-copy clone.
func (r *replicationAllStats) clone() *replicationAllStats {
if r == nil {
return nil
}
// Shallow copy
dst := *r
// Copy individual targets.
if dst.Targets != nil {
dst.Targets = make(map[string]replicationStats, len(dst.Targets))
for k, v := range r.Targets {
dst.Targets[k] = v
}
}
return &dst
}
//msgp:encode ignore dataUsageEntryV2 dataUsageEntryV3 dataUsageEntryV4 dataUsageEntryV5 dataUsageEntryV6
//msgp:marshal ignore dataUsageEntryV2 dataUsageEntryV3 dataUsageEntryV4 dataUsageEntryV5 dataUsageEntryV6
@ -413,14 +446,11 @@ func (e dataUsageEntry) clone() dataUsageEntry {
e.Children = ch
}
if e.ReplicationStats != nil {
// Copy to new struct
r := *e.ReplicationStats
e.ReplicationStats = &r
// Clone ReplicationStats
e.ReplicationStats = e.ReplicationStats.clone()
}
if e.AllTierStats != nil {
ats := newAllTierStats()
ats.merge(e.AllTierStats)
e.AllTierStats = ats
e.AllTierStats = e.AllTierStats.clone()
}
return e
}