pinning.go 1.4 KB

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