Reorganize mount/unmount code so it is easier to add Darwin-specific implementation
After these changes, in order to add Darwin bind-mount implementation, one only needs: * Adjust HasBindMounts definition in mount.go * Provide implementation in mount_darwin.go There was no consensus on adding dependency on bindfs, that seems to be the only working solution for bind-mounts on Darwin as of today, in https://github.com/containerd/containerd/pull/8789, that's why the actual implementation is not added in current PR. As a bonus, Linux FUSE-related code was moved to a separate file and possibly could be reused on FreeBSD, though this needs testing. Signed-off-by: Marat Radchenko <marat@slonopotamus.org>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
//go:build !windows && !darwin && !openbsd
|
||||
//go:build !windows && !openbsd
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
@@ -19,10 +19,13 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/moby/sys/mountinfo"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// UnmountRecursive unmounts the target and all mounts underneath, starting
|
||||
@@ -69,3 +72,64 @@ func UnmountRecursive(target string, flags int) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmount(target string, flags int) error {
|
||||
if isFUSE(target) {
|
||||
// TODO: Why error is ignored?
|
||||
// Shouldn't this just be unconditional "return unmountFUSE(target)"?
|
||||
if err := unmountFUSE(target); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
for i := 0; i < 50; i++ {
|
||||
if err := unix.Unmount(target, flags); err != nil {
|
||||
switch err {
|
||||
case unix.EBUSY:
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
continue
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("failed to unmount target %s: %w", target, unix.EBUSY)
|
||||
}
|
||||
|
||||
// Unmount the provided mount path with the flags
|
||||
func Unmount(target string, flags int) error {
|
||||
if err := unmount(target, flags); err != nil && err != unix.EINVAL {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmountAll repeatedly unmounts the given mount point until there
|
||||
// are no mounts remaining (EINVAL is returned by mount), which is
|
||||
// useful for undoing a stack of mounts on the same mount point.
|
||||
// UnmountAll all is noop when the first argument is an empty string.
|
||||
// This is done when the containerd client did not specify any rootfs
|
||||
// mounts (e.g. because the rootfs is managed outside containerd)
|
||||
// UnmountAll is noop when the mount path does not exist.
|
||||
func UnmountAll(mount string, flags int) error {
|
||||
if mount == "" {
|
||||
return nil
|
||||
}
|
||||
if _, err := os.Stat(mount); os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
for {
|
||||
if err := unmount(mount, flags); err != nil {
|
||||
// EINVAL is returned if the target is not a
|
||||
// mount point, indicating that we are
|
||||
// done. It can also indicate a few other
|
||||
// things (such as invalid flags) which we
|
||||
// unfortunately end up squelching here too.
|
||||
if err == unix.EINVAL {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user