github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/graphdriver/aufs/mount.go (about)

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