fix: safe update of the audit objectErasureMap (#12477)

objectErasureMap in the audit holds information about the objects
involved in the current S3 operation such as pool index, set an index,
and disk endpoints. One user saw a crash due to a concurrent update of
objectErasureMap information. Use sync.Map to prevent a crash.
This commit is contained in:
Anis Elleuch 2021-06-09 18:51:19 +01:00 committed by GitHub
parent dd5e9493f1
commit 8e9e028c0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 20 additions and 4 deletions

View File

@ -20,6 +20,7 @@ package cmd
import ( import (
"context" "context"
"encoding/binary" "encoding/binary"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"hash/crc32" "hash/crc32"
@ -521,6 +522,21 @@ type auditObjectOp struct {
Disks []string `json:"disks"` Disks []string `json:"disks"`
} }
type auditObjectErasureMap struct {
sync.Map
}
// Define how to marshal auditObjectErasureMap so it can be
// printed in the audit webhook notification request.
func (a *auditObjectErasureMap) MarshalJSON() ([]byte, error) {
mapCopy := make(map[string]auditObjectOp)
a.Range(func(k, v interface{}) bool {
mapCopy[k.(string)] = v.(auditObjectOp)
return true
})
return json.Marshal(mapCopy)
}
func auditObjectErasureSet(ctx context.Context, object string, set *erasureObjects) { func auditObjectErasureSet(ctx context.Context, object string, set *erasureObjects) {
if len(logger.AuditTargets) == 0 { if len(logger.AuditTargets) == 0 {
return return
@ -534,20 +550,20 @@ func auditObjectErasureSet(ctx context.Context, object string, set *erasureObjec
Disks: set.getEndpoints(), Disks: set.getEndpoints(),
} }
var objectErasureSetTag map[string]auditObjectOp var objectErasureSetTag *auditObjectErasureMap
reqInfo := logger.GetReqInfo(ctx) reqInfo := logger.GetReqInfo(ctx)
for _, kv := range reqInfo.GetTags() { for _, kv := range reqInfo.GetTags() {
if kv.Key == objectErasureMapKey { if kv.Key == objectErasureMapKey {
objectErasureSetTag = kv.Val.(map[string]auditObjectOp) objectErasureSetTag = kv.Val.(*auditObjectErasureMap)
break break
} }
} }
if objectErasureSetTag == nil { if objectErasureSetTag == nil {
objectErasureSetTag = make(map[string]auditObjectOp) objectErasureSetTag = &auditObjectErasureMap{}
} }
objectErasureSetTag[object] = op objectErasureSetTag.Store(object, op)
reqInfo.SetTags(objectErasureMapKey, objectErasureSetTag) reqInfo.SetTags(objectErasureMapKey, objectErasureSetTag)
} }