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