mount.go 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. //go:build linux
  2. // +build linux
  3. package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
  4. import (
  5. "os/exec"
  6. "syscall"
  7. "time"
  8. "github.com/moby/sys/mount"
  9. "github.com/pkg/errors"
  10. "golang.org/x/sys/unix"
  11. )
  12. // Unmount the target specified.
  13. func Unmount(target string) error {
  14. const retries = 5
  15. // auplink flush
  16. for i := 0; ; i++ {
  17. out, err := exec.Command("auplink", target, "flush").CombinedOutput()
  18. if err == nil {
  19. break
  20. }
  21. rc := 0
  22. if exiterr, ok := err.(*exec.ExitError); ok {
  23. if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
  24. rc = status.ExitStatus()
  25. }
  26. }
  27. if i >= retries || rc != int(unix.EINVAL) {
  28. logger.WithError(err).WithField("method", "Unmount").Warnf("auplink flush failed: %s", out)
  29. break
  30. }
  31. // auplink failed to find target in /proc/self/mounts because
  32. // kernel can't guarantee continuity while reading from it
  33. // while mounts table is being changed
  34. logger.Debugf("auplink flush error (retrying %d/%d): %s", i+1, retries, out)
  35. }
  36. // unmount
  37. var err error
  38. for i := 0; i < retries; i++ {
  39. err = mount.Unmount(target)
  40. if err != nil && errors.Is(err, unix.EBUSY) {
  41. logger.Debugf("aufs unmount %s failed with EBUSY (retrying %d/%d)", target, i+1, retries)
  42. time.Sleep(100 * time.Millisecond)
  43. continue // try again
  44. }
  45. break
  46. }
  47. // either no error occurred, or another error
  48. return err
  49. }