pinning.go 1.8 KB

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