Today I was looking into RecursiveUnmount code and thought we can optimize it by adding the fast path, like this:
// RecursiveUnmount unmounts the target and all mounts underneath, starting with
// the deepsest mount first.
func RecursiveUnmount(target string) error {
+ // Fast path: if we can unmount target, there are no submounts!
+ if err := unmount(target, 0); err == nil {
+ return nil
+ }
+
mounts, err := mountinfo.GetMounts(mountinfo.PrefixFilter(target))
if err != nil {
return err
The idea is, if there are other mounts under target, we'll go the usual slow way, but if not, all it takes a single syscall.
When I read the umount(2) man page for the umphteen time, to confirm my gut feeling I should NOT use MNT_DETACH in the fast path, and found this gem:
immediately disconnect the filesystem and all filesystems
mounted below it from each other and from the mount table
This means that MNT_DETACH performs a recursive unmount. Since we do use MNT_DETACH from RecursiveUnmount anyway, it seems all of it, in its entirety, can be replaced by a single umount(2) with MNT_DETACH.
@cpuguy83 can you please shed some light on how you came with RecursiveUnmount in the first place? I tracked its inception down to PR moby/moby#31012 (moby/moby@54dcbab#diff-ce9e7d50400d88435b2be4f4cd9b7b23R61) but it's not very clear why it was added. I am surely very interested in your other input on this topic.
Today I was looking into RecursiveUnmount code and thought we can optimize it by adding the fast path, like this:
// RecursiveUnmount unmounts the target and all mounts underneath, starting with // the deepsest mount first. func RecursiveUnmount(target string) error { + // Fast path: if we can unmount target, there are no submounts! + if err := unmount(target, 0); err == nil { + return nil + } + mounts, err := mountinfo.GetMounts(mountinfo.PrefixFilter(target)) if err != nil { return errThe idea is, if there are other mounts under
target, we'll go the usual slow way, but if not, all it takes a single syscall.When I read the umount(2) man page for the umphteen time, to confirm my gut feeling I should NOT use MNT_DETACH in the fast path, and found this gem:
This means that MNT_DETACH performs a recursive unmount. Since we do use MNT_DETACH from RecursiveUnmount anyway, it seems all of it, in its entirety, can be replaced by a single
umount(2)with MNT_DETACH.@cpuguy83 can you please shed some light on how you came with RecursiveUnmount in the first place? I tracked its inception down to PR moby/moby#31012 (moby/moby@54dcbab#diff-ce9e7d50400d88435b2be4f4cd9b7b23R61) but it's not very clear why it was added. I am surely very interested in your other input on this topic.