| /* |
| Copyright 2018 The Kubernetes Authors. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| package mount |
| |
| import ( |
| "fmt" |
| "os" |
| |
| "k8s.io/klog/v2" |
| ) |
| |
| // CleanupMountPoint unmounts the given path and deletes the remaining directory |
| // if successful. If extensiveMountPointCheck is true IsNotMountPoint will be |
| // called instead of IsLikelyNotMountPoint. IsNotMountPoint is more expensive |
| // but properly handles bind mounts within the same fs. |
| func CleanupMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool) error { |
| pathExists, pathErr := PathExists(mountPath) |
| if !pathExists { |
| klog.Warningf("Warning: Unmount skipped because path does not exist: %v", mountPath) |
| return nil |
| } |
| corruptedMnt := IsCorruptedMnt(pathErr) |
| if pathErr != nil && !corruptedMnt { |
| return fmt.Errorf("Error checking path: %v", pathErr) |
| } |
| return doCleanupMountPoint(mountPath, mounter, extensiveMountPointCheck, corruptedMnt) |
| } |
| |
| // doCleanupMountPoint unmounts the given path and |
| // deletes the remaining directory if successful. |
| // if extensiveMountPointCheck is true |
| // IsNotMountPoint will be called instead of IsLikelyNotMountPoint. |
| // IsNotMountPoint is more expensive but properly handles bind mounts within the same fs. |
| // if corruptedMnt is true, it means that the mountPath is a corrupted mountpoint, and the mount point check |
| // will be skipped |
| func doCleanupMountPoint(mountPath string, mounter Interface, extensiveMountPointCheck bool, corruptedMnt bool) error { |
| var notMnt bool |
| var err error |
| if !corruptedMnt { |
| if extensiveMountPointCheck { |
| notMnt, err = IsNotMountPoint(mounter, mountPath) |
| } else { |
| notMnt, err = mounter.IsLikelyNotMountPoint(mountPath) |
| } |
| |
| if err != nil { |
| return err |
| } |
| |
| if notMnt { |
| klog.Warningf("Warning: %q is not a mountpoint, deleting", mountPath) |
| return os.Remove(mountPath) |
| } |
| } |
| |
| // Unmount the mount path |
| klog.V(4).Infof("%q is a mountpoint, unmounting", mountPath) |
| if err := mounter.Unmount(mountPath); err != nil { |
| return err |
| } |
| |
| if extensiveMountPointCheck { |
| notMnt, err = IsNotMountPoint(mounter, mountPath) |
| } else { |
| notMnt, err = mounter.IsLikelyNotMountPoint(mountPath) |
| } |
| if err != nil { |
| return err |
| } |
| if notMnt { |
| klog.V(4).Infof("%q is unmounted, deleting the directory", mountPath) |
| return os.Remove(mountPath) |
| } |
| return fmt.Errorf("Failed to unmount path %v", mountPath) |
| } |
| |
| // PathExists returns true if the specified path exists. |
| // TODO: clean this up to use pkg/util/file/FileExists |
| func PathExists(path string) (bool, error) { |
| _, err := os.Stat(path) |
| if err == nil { |
| return true, nil |
| } else if os.IsNotExist(err) { |
| return false, nil |
| } else if IsCorruptedMnt(err) { |
| return true, err |
| } |
| return false, err |
| } |