From c8ca055935f21e8b740292d0c30b221ea8a21d3a Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Tue, 24 Aug 2021 16:11:38 +0200 Subject: [PATCH] Fix concurrent map read/write (#13052) Clones were not independent. Fixes race: ``` WARNING: DATA RACE Read at 0x00c002040cc0 by goroutine 50: runtime.mapiterinit() c:/go/src/runtime/map.go:802 +0x0 github.com/minio/minio/cmd.(*dataUsageCache).flatten() d:/minio/minio/cmd/data-usage-cache.go:551 +0xad github.com/minio/minio/cmd.(*dataUsageCache).dui() d:/minio/minio/cmd/data-usage-cache.go:352 +0x144 github.com/minio/minio/cmd.(*erasureServerPools).NSScanner.func3.1() d:/minio/minio/cmd/erasure-server-pool.go:542 +0x2a4 github.com/minio/minio/cmd.(*erasureServerPools).NSScanner.func3() d:/minio/minio/cmd/erasure-server-pool.go:561 +0x24b Previous write at 0x00c002040cc0 by goroutine 1391: runtime.mapassign_faststr() c:/go/src/runtime/map_faststr.go:202 +0x0 github.com/minio/minio/cmd.(*dataUsageEntry).addChild() d:/minio/minio/cmd/data-usage-cache.go:231 +0x313 github.com/minio/minio/cmd.(*dataUsageCache).replace() d:/minio/minio/cmd/data-usage-cache.go:383 +0x293 github.com/minio/minio/cmd.erasureObjects.nsScanner.func1() d:/minio/minio/cmd/erasure.go:428 +0x3a6 ``` --- cmd/data-usage-cache.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/cmd/data-usage-cache.go b/cmd/data-usage-cache.go index ea802a18c..bb6ef11d8 100644 --- a/cmd/data-usage-cache.go +++ b/cmd/data-usage-cache.go @@ -238,6 +238,24 @@ func (e *dataUsageEntry) removeChild(hash dataUsageHash) { } } +// Create a clone of the entry. +func (e dataUsageEntry) clone() dataUsageEntry { + // We operate on a copy from the receiver. + if e.Children != nil { + ch := make(dataUsageHashMap, len(e.Children)) + for k, v := range e.Children { + ch[k] = v + } + e.Children = ch + } + if e.ReplicationStats != nil { + // Copy to new struct + r := *e.ReplicationStats + e.ReplicationStats = &r + } + return e +} + // find a path in the cache. // Returns nil if not found. func (d *dataUsageCache) find(path string) *dataUsageEntry { @@ -672,7 +690,7 @@ func (d *dataUsageCache) clone() dataUsageCache { Cache: make(map[string]dataUsageEntry, len(d.Cache)), } for k, v := range d.Cache { - clone.Cache[k] = v + clone.Cache[k] = v.clone() } return clone }