pinning.go (1797B)
1 package internal 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "runtime" 9 "unsafe" 10 11 "github.com/cilium/ebpf/internal/sys" 12 "github.com/cilium/ebpf/internal/unix" 13 ) 14 15 func Pin(currentPath, newPath string, fd *sys.FD) error { 16 const bpfFSType = 0xcafe4a11 17 18 if newPath == "" { 19 return errors.New("given pinning path cannot be empty") 20 } 21 if currentPath == newPath { 22 return nil 23 } 24 25 var statfs unix.Statfs_t 26 if err := unix.Statfs(filepath.Dir(newPath), &statfs); err != nil { 27 return err 28 } 29 30 fsType := int64(statfs.Type) 31 if unsafe.Sizeof(statfs.Type) == 4 { 32 // We're on a 32 bit arch, where statfs.Type is int32. bpfFSType is a 33 // negative number when interpreted as int32 so we need to cast via 34 // uint32 to avoid sign extension. 35 fsType = int64(uint32(statfs.Type)) 36 } 37 38 if fsType != bpfFSType { 39 return fmt.Errorf("%s is not on a bpf filesystem", newPath) 40 } 41 42 defer runtime.KeepAlive(fd) 43 44 if currentPath == "" { 45 return sys.ObjPin(&sys.ObjPinAttr{ 46 Pathname: sys.NewStringPointer(newPath), 47 BpfFd: fd.Uint(), 48 }) 49 } 50 51 // Renameat2 is used instead of os.Rename to disallow the new path replacing 52 // an existing path. 53 err := unix.Renameat2(unix.AT_FDCWD, currentPath, unix.AT_FDCWD, newPath, unix.RENAME_NOREPLACE) 54 if err == nil { 55 // Object is now moved to the new pinning path. 56 return nil 57 } 58 if !os.IsNotExist(err) { 59 return fmt.Errorf("unable to move pinned object to new path %v: %w", newPath, err) 60 } 61 // Internal state not in sync with the file system so let's fix it. 62 return sys.ObjPin(&sys.ObjPinAttr{ 63 Pathname: sys.NewStringPointer(newPath), 64 BpfFd: fd.Uint(), 65 }) 66 } 67 68 func Unpin(pinnedPath string) error { 69 if pinnedPath == "" { 70 return nil 71 } 72 err := os.Remove(pinnedPath) 73 if err == nil || os.IsNotExist(err) { 74 return nil 75 } 76 return err 77 }