1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 |
- //go:build linux
- // +build linux
- package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
- import (
- "os/exec"
- "syscall"
- "time"
- "github.com/moby/sys/mount"
- "github.com/pkg/errors"
- "golang.org/x/sys/unix"
- )
- // Unmount the target specified.
- func Unmount(target string) error {
- const retries = 5
- // auplink flush
- for i := 0; ; i++ {
- out, err := exec.Command("auplink", target, "flush").CombinedOutput()
- if err == nil {
- break
- }
- rc := 0
- if exiterr, ok := err.(*exec.ExitError); ok {
- if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
- rc = status.ExitStatus()
- }
- }
- if i >= retries || rc != int(unix.EINVAL) {
- logger.WithError(err).WithField("method", "Unmount").Warnf("auplink flush failed: %s", out)
- break
- }
- // auplink failed to find target in /proc/self/mounts because
- // kernel can't guarantee continuity while reading from it
- // while mounts table is being changed
- logger.Debugf("auplink flush error (retrying %d/%d): %s", i+1, retries, out)
- }
- // unmount
- var err error
- for i := 0; i < retries; i++ {
- err = mount.Unmount(target)
- if err != nil && errors.Is(err, unix.EBUSY) {
- logger.Debugf("aufs unmount %s failed with EBUSY (retrying %d/%d)", target, i+1, retries)
- time.Sleep(100 * time.Millisecond)
- continue // try again
- }
- break
- }
- // either no error occurred, or another error
- return err
- }
|