66 "fmt"
77 "io"
88 "os"
9+ "os/exec"
910 "path"
1011 "path/filepath"
1112 "strconv"
@@ -338,6 +339,24 @@ func ensureMountPoint(path string, mounter mount.Interface) (bool, error) {
338339 return isMnt , err
339340}
340341
342+ // ensureBindMountPoint evaluates whether a path is a valid mount point for bind mount.
343+ // In case the path does not exist, it will create a regular file for bind mount.
344+ // In case where the mount point exists, the mount point will be cleared and replaced by a new regular file.
345+ func ensureBindMountPoint (path string , mounter mount.Interface ) error {
346+ logrus .Infof ("Trying to ensure bind mount point %v" , path )
347+
348+ // blindly clean up the target mount point for recreation
349+ if cleanupErr := unmountAndCleanupMountPoint (path , mounter ); cleanupErr != nil {
350+ return errors .Wrapf (cleanupErr , "failed to remove corrupt bind mount point at %s" , path )
351+ }
352+
353+ // create regular file for bind mount
354+ if makeFileErr := makeFile (path ); makeFileErr != nil {
355+ return errors .Wrapf (makeFileErr , "failed to create regular file for bind mount at %s" , path )
356+ }
357+ return nil
358+ }
359+
341360// ensureDirectory checks if a folder exists at the specified path.
342361// If not, it creates the folder and returns true, otherwise returns false.
343362// If the path exists but is not a folder, it returns an error.
@@ -383,7 +402,16 @@ func unmount(path string, mounter mount.Interface) (err error) {
383402 return err
384403}
385404
386- // unmountAndCleanupMountPoint ensures all mount layers for the path are unmounted and the mount directory is removed
405+ func lazyUnmount (path string ) error {
406+ command := exec .Command ("umount" , "-l" , path )
407+ output , err := command .CombinedOutput ()
408+ if err != nil {
409+ return errors .Wrapf (err , "failed to lazy unmount a mount point %v, output: %s" , path , output )
410+ }
411+ return nil
412+ }
413+
414+ // unmountAndCleanupMountPoint ensures all mount layers for the path are unmounted and the mount point is removed
387415func unmountAndCleanupMountPoint (path string , mounter mount.Interface ) error {
388416 // we just try to unmount since the path check would get stuck for nfs mounts
389417 logrus .Infof ("Trying to umount mount point %v" , path )
@@ -392,8 +420,34 @@ func unmountAndCleanupMountPoint(path string, mounter mount.Interface) error {
392420 return err
393421 }
394422
423+ isMnt , validateUnmountErr := mounter .IsMountPoint (path )
424+ if validateUnmountErr != nil {
425+ return errors .Wrapf (validateUnmountErr , "failed to validate unmounted mount point %v" , path )
426+ }
427+ if isMnt {
428+ logrus .Warnf ("Mount point %v is still busy after unmount, trying to lazy unmount to release mount point" , path )
429+ if lazyUnmountErr := lazyUnmount (path ); lazyUnmountErr != nil {
430+ return errors .Wrapf (lazyUnmountErr , "failed to to release mount point %v" , path )
431+ }
432+ }
433+
395434 logrus .Infof ("Trying to clean up mount point %v" , path )
396- return mount .CleanupMountPoint (path , mounter , true )
435+ if err := mount .CleanupMountPoint (path , mounter , true ); err != nil {
436+ return err
437+ }
438+ // ensure the file is removed even when it is a broken symbolic link
439+ info , statErr := os .Lstat (path )
440+ if statErr != nil {
441+ if os .IsNotExist (statErr ) {
442+ return nil
443+ }
444+ return errors .Wrapf (statErr , "failed to check cleaned up mount point %v" , path )
445+ }
446+ logrus .WithField ("fileMode" , info .Mode ().String ()).Infof ("Mount point %v exists after mount-utils clean up, removing the file" , path )
447+ if rmErr := os .Remove (path ); rmErr != nil {
448+ return errors .Wrapf (rmErr , "failed to remove broken symbolic link mount point %v" , path )
449+ }
450+ return nil
397451}
398452
399453// isBlockDevice return true if volumePath file is a block device, false otherwise.
@@ -439,7 +493,7 @@ func getFilesystemStatistics(volumePath string) (*volumeFilesystemStatistics, er
439493 return volStats , nil
440494}
441495
442- // makeFile creates an empty file.
496+ // makeFile creates an empty regular file.
443497// If pathname already exists, whether a file or directory, no error is returned.
444498func makeFile (pathname string ) error {
445499 f , err := os .OpenFile (pathname , os .O_CREATE , os .FileMode (0644 ))
0 commit comments