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:
		| @@ -26,7 +26,6 @@ import ( | ||||
| 	"runtime" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/containerd/log" | ||||
| 	"github.com/moby/sys/userns" | ||||
| @@ -274,92 +273,6 @@ func doPrepareIDMappedOverlay(lowerDirs []string, usernsFd int) (tmpLowerDirs [] | ||||
| 	return tmpLowerDirs, cleanUp, nil | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| } | ||||
|  | ||||
| // fuseSuperMagic is defined in statfs(2) | ||||
| const fuseSuperMagic = 0x65735546 | ||||
|  | ||||
| func isFUSE(dir string) bool { | ||||
| 	var st unix.Statfs_t | ||||
| 	if err := unix.Statfs(dir, &st); err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	return st.Type == fuseSuperMagic | ||||
| } | ||||
|  | ||||
| // unmountFUSE attempts to unmount using fusermount/fusermount3 helper binary. | ||||
| // | ||||
| // For FUSE mounts, using these helper binaries is preferred, see: | ||||
| // https://github.com/containerd/containerd/pull/3765#discussion_r342083514 | ||||
| func unmountFUSE(target string) error { | ||||
| 	var err error | ||||
| 	for _, helperBinary := range []string{"fusermount3", "fusermount"} { | ||||
| 		cmd := exec.Command(helperBinary, "-u", target) | ||||
| 		err = cmd.Run() | ||||
| 		if err == nil { | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func unmount(target string, flags int) error { | ||||
| 	if isFUSE(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) | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // parseMountOptions takes fstab style mount options and parses them for | ||||
| // use with a standard mount() syscall | ||||
| func parseMountOptions(options []string) (opt mountOpt) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Marat Radchenko
					Marat Radchenko