Skip to content

Commit

Permalink
vars: have variable accessors return an error if the context is done
Browse files Browse the repository at this point in the history
The efivarfs kernel driver rate limits variable reads per-user, so
supporting cancellation / deadlines can be useful for functions that
make multiple use of variable accessors, such as
ReadOrderedLoadOptionVariables or ComputeSecureBootMode.

A future commit will make the efivarfs backend implement VarsBackend2
and plumb the context through for variable writes, which currently makes
use of a retry loop to handle races with other processes that change the
inode immutability flag, where cancellation will be more useful.
  • Loading branch information
chrisccoulson committed Jul 9, 2024
1 parent eea0b0a commit 34aec2e
Showing 1 changed file with 27 additions and 3 deletions.
30 changes: 27 additions & 3 deletions vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,23 @@ func (v nullVarsBackend) List() ([]VariableDescriptor, error) {
return nil, ErrVarsUnavailable
}

func isContextDone(ctx context.Context) error {
select {
case <-ctx.Done():
return ctx.Err()
default:
return nil
}
}

// ReadVariable returns the value and attributes of the EFI variable with the specified
// name and GUID. In general, [DefaultVarContext] should be supplied to this.
func ReadVariable(ctx context.Context, name string, guid GUID) ([]byte, VariableAttributes, error) {
attrs, data, err := getVarsBackend(ctx).Get(ctx, name, guid)
backend := getVarsBackend(ctx)
if err := isContextDone(ctx); err != nil {
return nil, 0, err
}
attrs, data, err := backend.Get(ctx, name, guid)
return data, attrs, err
}

Expand All @@ -123,16 +136,27 @@ func ReadVariable(ctx context.Context, name string, guid GUID) ([]byte, Variable
//
// If the variable does not exist, it will be created.
func WriteVariable(ctx context.Context, name string, guid GUID, attrs VariableAttributes, data []byte) error {
return getVarsBackend(ctx).Set(ctx, name, guid, attrs, data)
backend := getVarsBackend(ctx)
if err := isContextDone(ctx); err != nil {
return err
}
return backend.Set(ctx, name, guid, attrs, data)
}

// ListVariables returns a sorted list of variables that can be accessed. In
// general, [DefaultVarContext] should be supplied to this.
func ListVariables(ctx context.Context) ([]VariableDescriptor, error) {
names, err := getVarsBackend(ctx).List(ctx)
backend := getVarsBackend(ctx)
if err := isContextDone(ctx); err != nil {
return nil, err
}
names, err := backend.List(ctx)
if err != nil {
return nil, err
}
if err := isContextDone(ctx); err != nil {
return nil, err
}
sort.Stable(variableDescriptorSlice(names))
return names, nil
}
Expand Down

0 comments on commit 34aec2e

Please sign in to comment.