diff --git a/mount/mount.go b/mount/mount.go index 883f8df3..4a7bb27b 100644 --- a/mount/mount.go +++ b/mount/mount.go @@ -17,15 +17,26 @@ func Mount(device, target, mType, options string) error { return mount(device, target, mType, uintptr(flag), data) } -// Unmount lazily unmounts a filesystem on supported platforms, otherwise -// does a normal unmount. +// Unmount lazily unmounts a filesystem on supported platforms, otherwise does +// a normal unmount. If target is not a mount point, no error is returned. func Unmount(target string) error { return unmount(target, mntDetach) } -// RecursiveUnmount unmounts the target and all mounts underneath, starting with -// the deepsest mount first. +// RecursiveUnmount unmounts the target and all mounts underneath, starting +// with the deepest mount first. The argument does not have to be a mount +// point itself. func RecursiveUnmount(target string) error { + // Fast path, works if target is a mount point that can be unmounted. + // On Linux, mntDetach flag ensures a recursive unmount. For other + // platforms, if there are submounts, we'll get EBUSY (and fall back + // to the slow path). NOTE we do not ignore EINVAL here as target might + // not be a mount point itself (but there can be mounts underneath). + if err := unmountBare(target, mntDetach); err == nil { + return nil + } + + // Slow path: get all submounts, sort, unmount one by one. mounts, err := mountinfo.GetMounts(mountinfo.PrefixFilter(target)) if err != nil { return err diff --git a/mount/unmount_unix.go b/mount/unmount_unix.go index 1d1afeee..924d059a 100644 --- a/mount/unmount_unix.go +++ b/mount/unmount_unix.go @@ -4,8 +4,12 @@ package mount import "golang.org/x/sys/unix" +func unmountBare(target string, flags int) error { + return unix.Unmount(target, flags) +} + func unmount(target string, flags int) error { - err := unix.Unmount(target, flags) + err := unmountBare(target, flags) if err == nil || err == unix.EINVAL { // Ignore "not mounted" error here. Note the same error // can be returned if flags are invalid, so this code diff --git a/mount/unmount_unsupported.go b/mount/unmount_unsupported.go index eebc4ab8..4d6073ec 100644 --- a/mount/unmount_unsupported.go +++ b/mount/unmount_unsupported.go @@ -2,6 +2,10 @@ package mount -func unmount(target string, flag int) error { +func unmountBare(_ string, _ int) error { + panic("Not implemented") +} + +func unmount(_ string, _ int) error { panic("Not implemented") }