github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/internal/pinning.go (about) 1 package internal 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "runtime" 9 10 "github.com/cilium/ebpf/internal/sys" 11 "github.com/cilium/ebpf/internal/unix" 12 ) 13 14 func Pin(currentPath, newPath string, fd *sys.FD) error { 15 if newPath == "" { 16 return errors.New("given pinning path cannot be empty") 17 } 18 if currentPath == newPath { 19 return nil 20 } 21 22 fsType, err := FSType(filepath.Dir(newPath)) 23 if err != nil { 24 return err 25 } 26 if fsType != unix.BPF_FS_MAGIC { 27 return fmt.Errorf("%s is not on a bpf filesystem", newPath) 28 } 29 30 defer runtime.KeepAlive(fd) 31 32 if currentPath == "" { 33 return sys.ObjPin(&sys.ObjPinAttr{ 34 Pathname: sys.NewStringPointer(newPath), 35 BpfFd: fd.Uint(), 36 }) 37 } 38 39 // Renameat2 is used instead of os.Rename to disallow the new path replacing 40 // an existing path. 41 err = unix.Renameat2(unix.AT_FDCWD, currentPath, unix.AT_FDCWD, newPath, unix.RENAME_NOREPLACE) 42 if err == nil { 43 // Object is now moved to the new pinning path. 44 return nil 45 } 46 if !os.IsNotExist(err) { 47 return fmt.Errorf("unable to move pinned object to new path %v: %w", newPath, err) 48 } 49 // Internal state not in sync with the file system so let's fix it. 50 return sys.ObjPin(&sys.ObjPinAttr{ 51 Pathname: sys.NewStringPointer(newPath), 52 BpfFd: fd.Uint(), 53 }) 54 } 55 56 func Unpin(pinnedPath string) error { 57 if pinnedPath == "" { 58 return nil 59 } 60 err := os.Remove(pinnedPath) 61 if err == nil || os.IsNotExist(err) { 62 return nil 63 } 64 return err 65 }