unmountRecursive unmounts the target and all mounts underneath, starting with the deepest mount first.
(ctx context.Context, target string)
| 65 | // unmountRecursive unmounts the target and all mounts underneath, starting with |
| 66 | // the deepest mount first. |
| 67 | func unmountRecursive(ctx context.Context, target string) error { |
| 68 | target, err := mount.CanonicalizePath(target) |
| 69 | if err != nil { |
| 70 | return err |
| 71 | } |
| 72 | |
| 73 | toUnmount, err := mountinfo.GetMounts(mountinfo.PrefixFilter(target)) |
| 74 | if err != nil { |
| 75 | return err |
| 76 | } |
| 77 | |
| 78 | // Make the deepest mount be first |
| 79 | sort.Slice(toUnmount, func(i, j int) bool { |
| 80 | return len(toUnmount[i].Mountpoint) > len(toUnmount[j].Mountpoint) |
| 81 | }) |
| 82 | |
| 83 | for i, m := range toUnmount { |
| 84 | if err := mount.UnmountAll(m.Mountpoint, unix.MNT_DETACH); err != nil { |
| 85 | if i == len(toUnmount)-1 { // last mount |
| 86 | return err |
| 87 | } |
| 88 | // This is some submount, we can ignore this error for now, the final unmount will fail if this is a real problem |
| 89 | log.G(ctx).WithError(err).Debugf("failed to unmount submount %s", m.Mountpoint) |
| 90 | } |
| 91 | } |
| 92 | return nil |
| 93 | } |
| 94 | |
| 95 | // ensureRemoveAll wraps `os.RemoveAll` to check for specific errors that can |
| 96 | // often be remedied. |
no test coverage detected
searching dependent graphs…