@@ -369,6 +369,24 @@ func ensureMountPoint(path string, mounter mount.Interface) (bool, error) {
369369 return isMnt , err
370370}
371371
372+ // ensureBindMountPoint evaluates whether a path is a valid mount point for bind mount.
373+ // In case the path does not exist, it will create a regular file for bind mount.
374+ // In case where the mount point exists, the mount point will be cleared and replaced by a new regular file.
375+ func ensureBindMountPoint (path string , mounter mount.Interface ) error {
376+ logrus .Infof ("Trying to ensure bind mount point %v" , path )
377+
378+ // blindly clean up the target mount point for recreation
379+ if cleanupErr := unmountAndCleanupMountPoint (path , mounter ); cleanupErr != nil {
380+ return errors .Wrapf (cleanupErr , "failed to remove corrupt bind mount point at %s" , path )
381+ }
382+
383+ // create regular file for bind mount
384+ if makeFileErr := makeFile (path ); makeFileErr != nil {
385+ return errors .Wrapf (makeFileErr , "failed to create regular file for bind mount at %s" , path )
386+ }
387+ return nil
388+ }
389+
372390// ensureDirectory checks if a folder exists at the specified path.
373391// If not, it creates the folder and returns true, otherwise returns false.
374392// If the path exists but is not a folder, it returns an error.
@@ -392,6 +410,18 @@ func ensureDirectory(path string) (bool, error) {
392410 return false , fmt .Errorf ("path %v exists but is not a folder" , path )
393411}
394412
413+ func lazyUnmount (path string , exec utilexec.Interface ) (err error ) {
414+ lazyUnmountCmd := exec .Command ("umount" , "-l" , path )
415+ output , err := lazyUnmountCmd .CombinedOutput ()
416+ if err != nil {
417+ if isNotMountedError (err ) {
418+ return nil
419+ }
420+ return errors .Wrapf (err , "failed to lazy unmount a mount point %v, output: %s" , path , output )
421+ }
422+ return nil
423+ }
424+
395425func unmount (path string , mounter mount.Interface ) (err error ) {
396426 forceUnmounter , ok := mounter .(mount.MounterForceUnmounter )
397427 if ok {
@@ -401,20 +431,14 @@ func unmount(path string, mounter mount.Interface) (err error) {
401431 logrus .Infof ("Trying to unmount potential mount point %v" , path )
402432 err = mounter .Unmount (path )
403433 }
404- if err == nil {
405- return nil
406- }
407-
408- if strings .Contains (err .Error (), "not mounted" ) ||
409- strings .Contains (err .Error (), "no mount point specified" ) {
410- logrus .Infof ("No need for unmount not a mount point %v" , path )
434+ if err == nil || isNotMountedError (err ) {
411435 return nil
412436 }
413-
414- return err
437+ logrus . WithError ( err ). Warnf ( "Error occurred during unmount %v, trying to lazy unmount to release mount point" , path )
438+ return lazyUnmount ( path , utilexec . New ())
415439}
416440
417- // unmountAndCleanupMountPoint ensures all mount layers for the path are unmounted and the mount directory is removed
441+ // unmountAndCleanupMountPoint ensures all mount layers for the path are unmounted and the mount point is removed
418442func unmountAndCleanupMountPoint (path string , mounter mount.Interface ) error {
419443 // we just try to unmount since the path check would get stuck for nfs mounts
420444 logrus .Infof ("Trying to umount mount point %v" , path )
@@ -423,8 +447,20 @@ func unmountAndCleanupMountPoint(path string, mounter mount.Interface) error {
423447 return err
424448 }
425449
450+ // ensure the file is removed even when it is a broken symbolic link
426451 logrus .Infof ("Trying to clean up mount point %v" , path )
427- return mount .CleanupMountPoint (path , mounter , true )
452+ info , statErr := os .Lstat (path )
453+ if statErr != nil {
454+ if os .IsNotExist (statErr ) {
455+ return nil
456+ }
457+ return errors .Wrapf (statErr , "failed to check cleaned up mount point %v" , path )
458+ }
459+ logrus .WithField ("fileMode" , info .Mode ().String ()).Infof ("Mount point %v exists, removing the file" , path )
460+ if rmErr := os .Remove (path ); rmErr != nil {
461+ return errors .Wrapf (rmErr , "failed to remove mount point %v" , path )
462+ }
463+ return nil
428464}
429465
430466// isBlockDevice return true if volumePath file is a block device, false otherwise.
@@ -470,7 +506,7 @@ func getFilesystemStatistics(volumePath string) (*volumeFilesystemStatistics, er
470506 return volStats , nil
471507}
472508
473- // makeFile creates an empty file.
509+ // makeFile creates an empty regular file.
474510// If pathname already exists, whether a file or directory, no error is returned.
475511func makeFile (pathname string ) error {
476512 f , err := os .OpenFile (pathname , os .O_CREATE , os .FileMode (0644 ))
@@ -534,3 +570,11 @@ func parseNodeID(topology *csi.Topology) (string, error) {
534570 }
535571 return nodeId , nil
536572}
573+
574+ func isNotMountedError (err error ) bool {
575+ if err == nil {
576+ return false
577+ }
578+ return strings .Contains (err .Error (), "not mounted" ) ||
579+ strings .Contains (err .Error (), "no mount point specified" )
580+ }
0 commit comments