Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

btf: don't cache kernel BTF in LoadKernelSpec #676

Merged
merged 1 commit into from May 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 2 additions & 24 deletions btf/btf.go
Expand Up @@ -11,7 +11,6 @@ import (
"math"
"os"
"reflect"
"sync"

"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/sys"
Expand Down Expand Up @@ -255,32 +254,11 @@ func indexTypes(types []Type) (map[Type]TypeID, map[essentialName][]Type) {
return typeIDs, typesByName
}

var kernelBTF struct {
sync.Mutex
*Spec
}

// LoadKernelSpec returns the current kernel's BTF information.
//
// Requires a >= 5.5 kernel with CONFIG_DEBUG_INFO_BTF enabled. Returns
// ErrNotSupported if BTF is not enabled.
// Defaults to /sys/kernel/btf/vmlinux and falls back to scanning the file system
// for vmlinux ELFs. Returns an error wrapping ErrNotSupported if BTF is not enabled.
func LoadKernelSpec() (*Spec, error) {
kernelBTF.Lock()
defer kernelBTF.Unlock()

if kernelBTF.Spec != nil {
return kernelBTF.Spec, nil
}

var err error
kernelBTF.Spec, err = loadKernelSpec()
return kernelBTF.Spec, err
}

// loadKernelSpec attempts to load the raw vmlinux BTF blob at
// /sys/kernel/btf/vmlinux and falls back to scanning the file system
// for vmlinux ELFs.
func loadKernelSpec() (*Spec, error) {
fh, err := os.Open("/sys/kernel/btf/vmlinux")
if err == nil {
defer fh.Close()
Expand Down
2 changes: 1 addition & 1 deletion btf/btf_test.go
Expand Up @@ -182,7 +182,7 @@ func BenchmarkParseVmlinux(b *testing.B) {
}

func TestParseCurrentKernelBTF(t *testing.T) {
spec, err := loadKernelSpec()
spec, err := LoadKernelSpec()
testutils.SkipIfNotSupported(t, err)
if err != nil {
t.Fatal("Can't load BTF:", err)
Expand Down
36 changes: 30 additions & 6 deletions linker.go
Expand Up @@ -3,6 +3,7 @@ package ebpf
import (
"errors"
"fmt"
"sync"

"github.com/cilium/ebpf/asm"
"github.com/cilium/ebpf/btf"
Expand Down Expand Up @@ -140,12 +141,9 @@ func applyRelocations(insns asm.Instructions, local, target *btf.Spec) error {
return nil
}

if target == nil {
var err error
target, err = btf.LoadKernelSpec()
if err != nil {
return err
}
target, err := maybeLoadKernelBTF(target)
if err != nil {
return err
}

fixups, err := btf.CORERelocate(local, target, relos)
Expand Down Expand Up @@ -200,3 +198,29 @@ func fixupProbeReadKernel(ins *asm.Instruction) {
ins.Constant = int64(asm.FnProbeReadStr)
}
}

var kernelBTF struct {
sync.Mutex
spec *btf.Spec
}

// maybeLoadKernelBTF loads the current kernel's BTF if spec is nil, otherwise
// it returns spec unchanged.
//
// The kernel BTF is cached for the lifetime of the process.
func maybeLoadKernelBTF(spec *btf.Spec) (*btf.Spec, error) {
if spec != nil {
return spec, nil
}

kernelBTF.Lock()
defer kernelBTF.Unlock()

if kernelBTF.spec != nil {
return kernelBTF.spec, nil
}

var err error
kernelBTF.spec, err = btf.LoadKernelSpec()
return kernelBTF.spec, err
}
13 changes: 4 additions & 9 deletions prog.go
Expand Up @@ -801,17 +801,12 @@ func findTargetInKernel(spec *btf.Spec, name string, progType ProgramType, attac
return 0, errUnrecognizedAttachType
}

var (
target btf.Type
err error
)
if spec == nil {
spec, err = btf.LoadKernelSpec()
if err != nil {
return 0, fmt.Errorf("load kernel spec: %w", err)
}
spec, err := maybeLoadKernelBTF(spec)
if err != nil {
return 0, fmt.Errorf("load kernel spec: %w", err)
}

var target btf.Type
if isBTFTypeFunc {
var targetFunc *btf.Func
err = spec.TypeByName(typeName, &targetFunc)
Expand Down