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  }