diff --git a/map.go b/map.go index cf8680e16..ca8fbc702 100644 --- a/map.go +++ b/map.go @@ -18,6 +18,7 @@ var ( ErrKeyNotExist = errors.New("key does not exist") ErrKeyExist = errors.New("key already exists") ErrIterationAborted = errors.New("iteration aborted") + ErrMapIncompatible = errors.New("map's spec is incompatible with pinned map") ) // MapOptions control loading a map into the kernel. @@ -96,19 +97,19 @@ type MapKV struct { func (ms *MapSpec) checkCompatibility(m *Map) error { switch { case m.typ != ms.Type: - return fmt.Errorf("expected type %v, got %v", ms.Type, m.typ) + return fmt.Errorf("expected type %v, got %v: %w", ms.Type, m.typ, ErrMapIncompatible) case m.keySize != ms.KeySize: - return fmt.Errorf("expected key size %v, got %v", ms.KeySize, m.keySize) + return fmt.Errorf("expected key size %v, got %v: %w", ms.KeySize, m.keySize, ErrMapIncompatible) case m.valueSize != ms.ValueSize: - return fmt.Errorf("expected value size %v, got %v", ms.ValueSize, m.valueSize) + return fmt.Errorf("expected value size %v, got %v: %w", ms.ValueSize, m.valueSize, ErrMapIncompatible) case m.maxEntries != ms.MaxEntries: - return fmt.Errorf("expected max entries %v, got %v", ms.MaxEntries, m.maxEntries) + return fmt.Errorf("expected max entries %v, got %v: %w", ms.MaxEntries, m.maxEntries, ErrMapIncompatible) case m.flags != ms.Flags: - return fmt.Errorf("expected flags %v, got %v", ms.Flags, m.flags) + return fmt.Errorf("expected flags %v, got %v: %w", ms.Flags, m.flags, ErrMapIncompatible) } return nil } @@ -171,6 +172,8 @@ func NewMap(spec *MapSpec) (*Map, error) { // The caller is responsible for ensuring the process' rlimit is set // sufficiently high for locking memory during map creation. This can be done // by calling unix.Setrlimit with unix.RLIMIT_MEMLOCK prior to calling NewMapWithOptions. +// +// May return an error wrapping ErrMapIncompatible. func NewMapWithOptions(spec *MapSpec, opts MapOptions) (*Map, error) { handles := newHandleCache() defer handles.close() @@ -202,7 +205,7 @@ func newMapWithOptions(spec *MapSpec, opts MapOptions, handles *handleCache) (_ defer closeOnError(m) if err := spec.checkCompatibility(m); err != nil { - return nil, fmt.Errorf("use pinned map %s: %s", spec.Name, err) + return nil, fmt.Errorf("use pinned map %s: %w", spec.Name, err) } return m, nil diff --git a/map_test.go b/map_test.go index 7911cb2bb..78ee0cedc 100644 --- a/map_test.go +++ b/map_test.go @@ -1315,6 +1315,16 @@ func TestMapPinning(t *testing.T) { if value != 42 { t.Fatal("Pinning doesn't use pinned maps") } + + spec.KeySize = 8 + m3, err := NewMapWithOptions(spec, MapOptions{PinPath: tmp}) + if err == nil { + m3.Close() + t.Fatalf("Opening a pinned map with a mismatching spec did not fail") + } + if !errors.Is(err, ErrMapIncompatible) { + t.Fatalf("Opening a pinned map with a mismatching spec failed with the wrong error") + } } type benchValue struct {