1
0
mirror of https://github.com/lxc/incus.git synced 2026-02-05 09:46:19 +01:00

incusd/operations: Prevent concurrent access to metadata

Closes #2865

Signed-off-by: Stéphane Graber <stgraber@stgraber.org>
This commit is contained in:
Stéphane Graber
2026-02-04 17:10:33 +01:00
parent b234ba988c
commit bb6e2b09eb

View File

@@ -153,6 +153,7 @@ func OperationCreate(s *state.State, projectName string, opClass OperationClass,
op.SetEventServer(s.Events) op.SetEventServer(s.Events)
} }
// Validate and make a copy of the metadata to avoid concurrent reads/writes.
newMetadata, err := parseMetadata(opMetadata) newMetadata, err := parseMetadata(opMetadata)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -506,7 +507,7 @@ func (op *Operation) Render() (string, *api.Operation, error) {
op.lock.Lock() op.lock.Lock()
// Make a copy of the metadata to avoid concurrent reads/writes. // Make a read-only copy of the metadata to avoid concurrent reads/writes.
metadata := map[string]any{} metadata := map[string]any{}
for k, v := range op.metadata { for k, v := range op.metadata {
metadata[k] = v metadata[k] = v
@@ -592,6 +593,7 @@ func (op *Operation) UpdateMetadata(opMetadata any) error {
return errors.New("Read-only operations can't be updated") return errors.New("Read-only operations can't be updated")
} }
// Validate and make a copy of the metadata to avoid concurrent reads/writes.
newMetadata, err := parseMetadata(opMetadata) newMetadata, err := parseMetadata(opMetadata)
if err != nil { if err != nil {
return err return err
@@ -635,7 +637,6 @@ func (op *Operation) ExtendMetadata(metadata any) error {
// Get current metadata. // Get current metadata.
newMetadata := op.metadata newMetadata := op.metadata
op.lock.Unlock()
// Merge with current one. // Merge with current one.
if op.metadata == nil { if op.metadata == nil {
@@ -645,7 +646,6 @@ func (op *Operation) ExtendMetadata(metadata any) error {
} }
// Update the operation. // Update the operation.
op.lock.Lock()
op.updatedAt = time.Now() op.updatedAt = time.Now()
op.metadata = newMetadata op.metadata = newMetadata
op.lock.Unlock() op.lock.Unlock()
@@ -665,9 +665,18 @@ func (op *Operation) ID() string {
return op.id return op.id
} }
// Metadata returns the operation Metadata. // Metadata returns a read-only copy of the operation metadata.
func (op *Operation) Metadata() map[string]any { func (op *Operation) Metadata() map[string]any {
return op.metadata op.lock.Lock()
defer op.lock.Unlock()
// Make a read-only copy of the metadata to avoid concurrent reads/writes.
metadata := map[string]any{}
for k, v := range op.metadata {
metadata[k] = v
}
return metadata
} }
// URL returns the operation URL. // URL returns the operation URL.