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.
@@ -370,20 +389,34 @@ func unmount(path string, mounter mount.Interface) (err error) {
370389 logrus .Infof ("Trying to unmount potential mount point %v" , path )
371390 err = mounter .Unmount (path )
372391 }
373- if err == nil {
392+ if err != nil && (strings .Contains (err .Error (), "not mounted" ) ||
393+ strings .Contains (err .Error (), "no mount point specified" )) {
394+ logrus .Infof ("No need for unmount not a mount point %v" , path )
374395 return nil
375396 }
376397
377- if strings .Contains (err .Error (), "not mounted" ) ||
378- strings .Contains (err .Error (), "no mount point specified" ) {
379- logrus .Infof ("No need for unmount not a mount point %v" , path )
398+ // ensure the mount point is unmounted
399+ isStillMnt , validateUnmountErr := mounter .IsMountPoint (path )
400+ if validateUnmountErr != nil {
401+ if os .IsNotExist (validateUnmountErr ) {
402+ isStillMnt = false
403+ } else {
404+ return errors .Wrapf (validateUnmountErr , "failed to validate unmounted mount point %v" , path )
405+ }
406+ }
407+ if ! isStillMnt {
380408 return nil
381409 }
382410
411+ logrus .Warnf ("Mount point %v is still busy after unmount, trying to lazy unmount to release mount point" , path )
412+ lazyUnmountCmd := exec .Command ("umount" , "-l" , path )
413+ if output , err := lazyUnmountCmd .CombinedOutput (); err != nil {
414+ return errors .Wrapf (err , "failed to lazy unmount a mount point %v, output: %s" , path , output )
415+ }
383416 return err
384417}
385418
386- // unmountAndCleanupMountPoint ensures all mount layers for the path are unmounted and the mount directory is removed
419+ // unmountAndCleanupMountPoint ensures all mount layers for the path are unmounted and the mount point is removed
387420func unmountAndCleanupMountPoint (path string , mounter mount.Interface ) error {
388421 // we just try to unmount since the path check would get stuck for nfs mounts
389422 logrus .Infof ("Trying to umount mount point %v" , path )
@@ -392,8 +425,20 @@ func unmountAndCleanupMountPoint(path string, mounter mount.Interface) error {
392425 return err
393426 }
394427
428+ // ensure the file is removed even when it is a broken symbolic link
395429 logrus .Infof ("Trying to clean up mount point %v" , path )
396- return mount .CleanupMountPoint (path , mounter , true )
430+ info , statErr := os .Lstat (path )
431+ if statErr != nil {
432+ if os .IsNotExist (statErr ) {
433+ return nil
434+ }
435+ return errors .Wrapf (statErr , "failed to check cleaned up mount point %v" , path )
436+ }
437+ logrus .WithField ("fileMode" , info .Mode ().String ()).Infof ("Mount point %v exists, removing the file" , path )
438+ if rmErr := os .Remove (path ); rmErr != nil {
439+ return errors .Wrapf (rmErr , "failed to remove mount point %v" , path )
440+ }
441+ return nil
397442}
398443
399444// isBlockDevice return true if volumePath file is a block device, false otherwise.
@@ -439,7 +484,7 @@ func getFilesystemStatistics(volumePath string) (*volumeFilesystemStatistics, er
439484 return volStats , nil
440485}
441486
442- // makeFile creates an empty file.
487+ // makeFile creates an empty regular file.
443488// If pathname already exists, whether a file or directory, no error is returned.
444489func makeFile (pathname string ) error {
445490 f , err := os .OpenFile (pathname , os .O_CREATE , os .FileMode (0644 ))
0 commit comments