Repository: ceph/ceph-csi
Pull request #5203: util: do not use `mount-utils.IsLikelyNotMountPoint` anymore
Author: login: nixpanic
Created: 2025-03-07T16:15:38Z | Merged: 2025-03-14T10:27:13Z

`IsLikelyNotMountPoint()` is an optimized version for `IsMountPoint()`
which can not detect all type of mounts (anymore). The slower
`IsMountPoint()` is more safe to use. This can cause a slight
performance regression in the case there are many mountpoints on the
system, but correctness is more important than speed while mounting.

Fixes: #4633


Diff:
diff --git a/e2e/go.mod b/e2e/go.mod
index 92a96c56bd4..00171122886 100644
--- a/e2e/go.mod
+++ b/e2e/go.mod
@@ -16,6 +16,7 @@ require (
 	github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0
 	github.com/onsi/ginkgo/v2 v2.23.0
 	github.com/onsi/gomega v1.36.2
+	// when updating k8s.io modules, update the 'replace' section below too
 	k8s.io/api v0.32.2
 	k8s.io/apimachinery v0.32.2
 	k8s.io/client-go v12.0.0+incompatible
@@ -24,6 +25,18 @@ require (
 	k8s.io/pod-security-admission v0.32.2
 )
 
+replace (
+	k8s.io/api => k8s.io/api v0.32.2
+	k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.32.2
+	k8s.io/client-go => k8s.io/client-go v0.32.2
+	k8s.io/cri-client => k8s.io/cri-client v0.32.2
+	k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.32.2
+	k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.32.2
+	k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.32.2
+	k8s.io/kubectl => k8s.io/kubectl v0.32.2
+	k8s.io/kubelet => k8s.io/kubelet v0.32.2
+)
+
 require (
 	cel.dev/expr v0.19.1 // indirect
 	github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab // indirect
@@ -155,18 +168,5 @@ require (
 	sigs.k8s.io/yaml v1.4.0 // indirect
 )
 
-replace (
-	k8s.io/api => k8s.io/api v0.32.2
-	k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.32.2
-	k8s.io/client-go => k8s.io/client-go v0.32.2
-	k8s.io/cri-client => k8s.io/cri-client v0.32.2
-	k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.32.2
-	k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.32.2
-	k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.32.2
-	k8s.io/kubectl => k8s.io/kubectl v0.32.2
-	k8s.io/kubelet => k8s.io/kubelet v0.32.2
-	k8s.io/mount-utils => k8s.io/mount-utils v0.29.3
-)
-
 // version 3.9 is really old, don't use that!
 exclude github.com/openshift/api v3.9.0+incompatible
diff --git a/e2e/go.sum b/e2e/go.sum
index 533f033ea0a..e2a0c7e00bb 100644
--- a/e2e/go.sum
+++ b/e2e/go.sum
@@ -368,8 +368,8 @@ k8s.io/kubelet v0.32.2 h1:WFTSYdt3BB1aTApDuKNI16x/4MYqqX8WBBBBh3KupDg=
 k8s.io/kubelet v0.32.2/go.mod h1:cC1ms5RS+lu0ckVr6AviCQXHLSPKEBC3D5oaCBdTGkI=
 k8s.io/kubernetes v1.32.2 h1:mShetlA102UpjRVSGzB+5vjJwy8oPy8FMWrkTH5f37o=
 k8s.io/kubernetes v1.32.2/go.mod h1:tiIKO63GcdPRBHW2WiUFm3C0eoLczl3f7qi56Dm1W8I=
-k8s.io/mount-utils v0.29.3 h1:iEcqPP7Vv8UClH8nnMfovtmy/04fIloRW9JuSXykoZ0=
-k8s.io/mount-utils v0.29.3/go.mod h1:9IWJTMe8tG0MYMLEp60xK9GYVeCdA3g4LowmnVi+t9Y=
+k8s.io/mount-utils v0.32.2 h1:aDwp+ucWiVnDr/LpRg88/dsXf/vm6gI1VZkYH3+3+Vw=
+k8s.io/mount-utils v0.32.2/go.mod h1:Kun5c2svjAPx0nnvJKYQWhfeNW+O0EpzHgRhDcYoSY0=
 k8s.io/pod-security-admission v0.32.2 h1:zDfAb/t0LbNU3z0ZMHtCb1zp8x05gWCGhmBYpUptm9A=
 k8s.io/pod-security-admission v0.32.2/go.mod h1:yxMPB3i1pGMLfxbe4BiWMuowMD7cdHR32y4nCj4wH+s=
 k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
diff --git a/e2e/vendor/k8s.io/mount-utils/mount_helper_unix.go b/e2e/vendor/k8s.io/mount-utils/mount_helper_unix.go
index 9193e7c8d2b..1c603dca7a0 100644
--- a/e2e/vendor/k8s.io/mount-utils/mount_helper_unix.go
+++ b/e2e/vendor/k8s.io/mount-utils/mount_helper_unix.go
@@ -61,7 +61,13 @@ func IsCorruptedMnt(err error) bool {
 		underlyingError = err
 	}
 
-	return underlyingError == syscall.ENOTCONN || underlyingError == syscall.ESTALE || underlyingError == syscall.EIO || underlyingError == syscall.EACCES || underlyingError == syscall.EHOSTDOWN || underlyingError == syscall.EWOULDBLOCK
+	return errors.Is(underlyingError, syscall.ENOTCONN) ||
+		errors.Is(underlyingError, syscall.ESTALE) ||
+		errors.Is(underlyingError, syscall.EIO) ||
+		errors.Is(underlyingError, syscall.EACCES) ||
+		errors.Is(underlyingError, syscall.EHOSTDOWN) ||
+		errors.Is(underlyingError, syscall.EWOULDBLOCK) ||
+		errors.Is(underlyingError, syscall.ENODEV)
 }
 
 // MountInfo represents a single line in /proc/<pid>/mountinfo.
diff --git a/e2e/vendor/k8s.io/mount-utils/mount_linux.go b/e2e/vendor/k8s.io/mount-utils/mount_linux.go
index 7d180723047..439d5058941 100644
--- a/e2e/vendor/k8s.io/mount-utils/mount_linux.go
+++ b/e2e/vendor/k8s.io/mount-utils/mount_linux.go
@@ -33,7 +33,9 @@ import (
 	"time"
 
 	"github.com/moby/sys/mountinfo"
+	"golang.org/x/sys/unix"
 
+	inuserns "github.com/moby/sys/userns"
 	"k8s.io/klog/v2"
 	utilexec "k8s.io/utils/exec"
 )
@@ -55,6 +57,11 @@ const (
 	errNotMounted = "not mounted"
 )
 
+var (
+	// Error statx support since Linux 4.11, https://man7.org/linux/man-pages/man2/statx.2.html
+	errStatxNotSupport = errors.New("the statx syscall is not supported. At least Linux kernel 4.11 is needed")
+)
+
 // Mounter provides the default implementation of mount.Interface
 // for the linux platform.  This implementation assumes that the
 // kubelet is running in the host's root mount namespace.
@@ -105,6 +112,59 @@ func (mounter *Mounter) hasSystemd() bool {
 	return *mounter.withSystemd
 }
 
+// Map unix.Statfs mount flags ro, nodev, noexec, nosuid, noatime, relatime,
+// nodiratime to mount option flag strings.
+func getUserNSBindMountOptions(path string, statfs func(path string, buf *unix.Statfs_t) (err error)) ([]string, error) {
+	var s unix.Statfs_t
+	var mountOpts []string
+	if err := statfs(path, &s); err != nil {
+		return nil, &os.PathError{Op: "statfs", Path: path, Err: err}
+	}
+	flagMapping := map[int]string{
+		unix.MS_RDONLY:     "ro",
+		unix.MS_NODEV:      "nodev",
+		unix.MS_NOEXEC:     "noexec",
+		unix.MS_NOSUID:     "nosuid",
+		unix.MS_NOATIME:    "noatime",
+		unix.MS_RELATIME:   "relatime",
+		unix.MS_NODIRATIME: "nodiratime",
+	}
+	for k, v := range flagMapping {
+		if int(s.Flags)&k == k {
+			mountOpts = append(mountOpts, v)
+		}
+	}
+	return mountOpts, nil
+}
+
+// Do a bind mount including the needed remount for applying the bind opts.
+// If the remount fails and we are running in a user namespace
+// figure out if the source filesystem has the ro, nodev, noexec, nosuid,
+// noatime, relatime or nodiratime flag set and try another remount with the found flags.
+func (mounter *Mounter) bindMountSensitive(mounterPath string, mountCmd string, source string, target string, fstype string, bindOpts []string, bindRemountOpts []string, bindRemountOptsSensitive []string, mountFlags []string, systemdMountRequired bool) error {
+	err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, mountFlags, systemdMountRequired)
+	if err != nil {
+		return err
+	}
+	err = mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, mountFlags, systemdMountRequired)
+	if inuserns.RunningInUserNS() {
+		if err == nil {
+			return nil
+		}
+		// Check if the source has ro, nodev, noexec, nosuid, noatime, relatime,
+		// nodiratime flag...
+		fixMountOpts, err := getUserNSBindMountOptions(source, unix.Statfs)
+		if err != nil {
+			return &os.PathError{Op: "statfs", Path: source, Err: err}
+		}
+		// ... and retry the mount with flags found above.
+		bindRemountOpts = append(bindRemountOpts, fixMountOpts...)
+		return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, mountFlags, systemdMountRequired)
+	} else {
+		return err
+	}
+}
+
 // Mount mounts source to target as fstype with given options. 'source' and 'fstype' must
 // be an empty string in case it's not required, e.g. for remount, or for auto filesystem
 // type, where kernel handles fstype for you. The mount 'options' is a list of options,
@@ -125,11 +185,7 @@ func (mounter *Mounter) MountSensitive(source string, target string, fstype stri
 	mounterPath := ""
 	bind, bindOpts, bindRemountOpts, bindRemountOptsSensitive := MakeBindOptsSensitive(options, sensitiveOptions)
 	if bind {
-		err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd)
-		if err != nil {
-			return err
-		}
-		return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd)
+		return mounter.bindMountSensitive(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd)
 	}
 	// The list of filesystems that require containerized mounter on GCI image cluster
 	fsTypesNeedMounter := map[string]struct{}{
@@ -154,11 +210,7 @@ func (mounter *Mounter) MountSensitiveWithoutSystemdWithMountFlags(source string
 	mounterPath := ""
 	bind, bindOpts, bindRemountOpts, bindRemountOptsSensitive := MakeBindOptsSensitive(options, sensitiveOptions)
 	if bind {
-		err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, mountFlags, false)
-		if err != nil {
-			return err
-		}
-		return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, mountFlags, false)
+		return mounter.bindMountSensitive(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOpts, bindRemountOptsSensitive, mountFlags, false)
 	}
 	// The list of filesystems that require containerized mounter on GCI image cluster
 	fsTypesNeedMounter := map[string]struct{}{
@@ -385,14 +437,20 @@ func (*Mounter) List() ([]MountPoint, error) {
 	return ListProcMounts(procMountsPath)
 }
 
-// IsLikelyNotMountPoint determines if a directory is not a mountpoint.
-// It is fast but not necessarily ALWAYS correct. If the path is in fact
-// a bind mount from one part of a mount to another it will not be detected.
-// It also can not distinguish between mountpoints and symbolic links.
-// mkdir /tmp/a /tmp/b; mount --bind /tmp/a /tmp/b; IsLikelyNotMountPoint("/tmp/b")
-// will return true. When in fact /tmp/b is a mount point. If this situation
-// is of interest to you, don't use this function...
-func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
+func statx(file string) (unix.Statx_t, error) {
+	var stat unix.Statx_t
+	if err := unix.Statx(unix.AT_FDCWD, file, unix.AT_STATX_DONT_SYNC, 0, &stat); err != nil {
+		if err == unix.ENOSYS {
+			return stat, errStatxNotSupport
+		}
+
+		return stat, err
+	}
+
+	return stat, nil
+}
+
+func (mounter *Mounter) isLikelyNotMountPointStat(file string) (bool, error) {
 	stat, err := os.Stat(file)
 	if err != nil {
 		return true, err
@@ -409,6 +467,51 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
 	return true, nil
 }
 
+func (mounter *Mounter) isLikelyNotMountPointStatx(file string) (bool, error) {
+	var stat, rootStat unix.Statx_t
+	var err error
+
+	if stat, err = statx(file); err != nil {
+		return true, err
+	}
+
+	if stat.Attributes_mask != 0 {
+		if stat.Attributes_mask&unix.STATX_ATTR_MOUNT_ROOT != 0 {
+			if stat.Attributes&unix.STATX_ATTR_MOUNT_ROOT != 0 {
+				// file is a mountpoint
+				return false, nil
+			} else {
+				// no need to check rootStat if unix.STATX_ATTR_MOUNT_ROOT supported
+				return true, nil
+			}
+		}
+	}
+
+	root := filepath.Dir(strings.TrimSuffix(file, "/"))
+	if rootStat, err = statx(root); err != nil {
+		return true, err
+	}
+
+	return (stat.Dev_major == rootStat.Dev_major && stat.Dev_minor == rootStat.Dev_minor), nil
+}
+
+// IsLikelyNotMountPoint determines if a directory is not a mountpoint.
+// It is fast but not necessarily ALWAYS correct. If the path is in fact
+// a bind mount from one part of a mount to another it will not be detected.
+// It also can not distinguish between mountpoints and symbolic links.
+// mkdir /tmp/a /tmp/b; mount --bind /tmp/a /tmp/b; IsLikelyNotMountPoint("/tmp/b")
+// will return true. When in fact /tmp/b is a mount point. If this situation
+// is of interest to you, don't use this function...
+func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
+	notMountPoint, err := mounter.isLikelyNotMountPointStatx(file)
+	if errors.Is(err, errStatxNotSupport) {
+		// fall back to isLikelyNotMountPointStat
+		return mounter.isLikelyNotMountPointStat(file)
+	}
+
+	return notMountPoint, err
+}
+
 // CanSafelySkipMountPointCheck relies on the detected behavior of umount when given a target that is not a mount point.
 func (mounter *Mounter) CanSafelySkipMountPointCheck() bool {
 	return mounter.withSafeNotMountedBehavior
@@ -520,7 +623,7 @@ func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target
 			sensitiveOptionsLog := sanitizedOptionsForLogging(options, sensitiveOptions)
 			detailedErr := fmt.Sprintf("format of disk %q failed: type:(%q) target:(%q) options:(%q) errcode:(%v) output:(%v) ", source, fstype, target, sensitiveOptionsLog, err, string(output))
 			klog.Error(detailedErr)
-			return NewMountError(FormatFailed, detailedErr)
+			return NewMountError(FormatFailed, "%s", detailedErr)
 		}
 
 		klog.Infof("Disk successfully formatted (mkfs): %s - %s %s", fstype, source, target)
@@ -528,7 +631,7 @@ func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target
 		if fstype != existingFormat {
 			// Verify that the disk is formatted with filesystem type we are expecting
 			mountErrorValue = FilesystemMismatch
-			klog.Warningf("Configured to mount disk %s as %s but current format is %s, things might break", source, existingFormat, fstype)
+			klog.Warningf("Configured to mount disk %s as %s but current format is %s, things might break", source, fstype, existingFormat)
 		}
 
 		if !readOnly {
@@ -543,7 +646,7 @@ func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target
 	// Mount the disk
 	klog.V(4).Infof("Attempting to mount disk %s in %s format at %s", source, fstype, target)
 	if err := mounter.MountSensitive(source, target, fstype, options, sensitiveOptions); err != nil {
-		return NewMountError(mountErrorValue, err.Error())
+		return NewMountError(mountErrorValue, "%s", err.Error())
 	}
 
 	return nil
diff --git a/e2e/vendor/k8s.io/mount-utils/mount_windows.go b/e2e/vendor/k8s.io/mount-utils/mount_windows.go
index be714646ec1..9c8ad054f8a 100644
--- a/e2e/vendor/k8s.io/mount-utils/mount_windows.go
+++ b/e2e/vendor/k8s.io/mount-utils/mount_windows.go
@@ -164,7 +164,7 @@ func (mounter *Mounter) MountSensitive(source string, target string, fstype stri
 // return (output, error)
 func newSMBMapping(username, password, remotepath string) (string, error) {
 	if username == "" || password == "" || remotepath == "" {
-		return "", fmt.Errorf("invalid parameter(username: %s, password: %s, remoteapth: %s)", username, sensitiveOptionsRemoved, remotepath)
+		return "", fmt.Errorf("invalid parameter(username: %s, password: %s, remotepath: %s)", username, sensitiveOptionsRemoved, remotepath)
 	}
 
 	// use PowerShell Environment Variables to store user input string to prevent command line injection
@@ -193,8 +193,8 @@ func isSMBMappingExist(remotepath string) bool {
 // check whether remotepath is valid
 // return (true, nil) if remotepath is valid
 func isValidPath(remotepath string) (bool, error) {
-	cmd := exec.Command("powershell", "/c", `Test-Path $Env:remoteapth`)
-	cmd.Env = append(os.Environ(), fmt.Sprintf("remoteapth=%s", remotepath))
+	cmd := exec.Command("powershell", "/c", `Test-Path $Env:remotepath`)
+	cmd.Env = append(os.Environ(), fmt.Sprintf("remotepath=%s", remotepath))
 	output, err := cmd.CombinedOutput()
 	if err != nil {
 		return false, fmt.Errorf("returned output: %s, error: %v", string(output), err)
diff --git a/e2e/vendor/modules.txt b/e2e/vendor/modules.txt
index 729c72a96d5..ffcc5ce34ad 100644
--- a/e2e/vendor/modules.txt
+++ b/e2e/vendor/modules.txt
@@ -1648,8 +1648,8 @@ k8s.io/kubernetes/test/utils/kubeconfig
 k8s.io/kubernetes/third_party/forked/golang/expansion
 k8s.io/kubernetes/third_party/forked/libcontainer/apparmor
 k8s.io/kubernetes/third_party/forked/libcontainer/utils
-# k8s.io/mount-utils v0.32.2 => k8s.io/mount-utils v0.29.3
-## explicit; go 1.21
+# k8s.io/mount-utils v0.32.2
+## explicit; go 1.23.0
 k8s.io/mount-utils
 # k8s.io/pod-security-admission v0.32.2
 ## explicit; go 1.23.0
@@ -1708,4 +1708,3 @@ sigs.k8s.io/yaml/goyaml.v2
 # k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.32.2
 # k8s.io/kubectl => k8s.io/kubectl v0.32.2
 # k8s.io/kubelet => k8s.io/kubelet v0.32.2
-# k8s.io/mount-utils => k8s.io/mount-utils v0.29.3
diff --git a/go.mod b/go.mod
index 0a18db35be6..30e55fb316f 100644
--- a/go.mod
+++ b/go.mod
@@ -39,6 +39,7 @@ require (
 	k8s.io/cloud-provider v0.32.2
 	k8s.io/klog/v2 v2.130.1
 	k8s.io/kubernetes v1.32.2
+	k8s.io/mount-utils v0.32.2
 	k8s.io/utils v0.0.0-20241210054802-24370beab758
 )
 
@@ -50,11 +51,6 @@ require (
 
 replace k8s.io/client-go => k8s.io/client-go v0.32.2
 
-// TODO: replaced by v0.29.3 until https://github.com/ceph/ceph-csi/issues/4633 is fixed
-require k8s.io/mount-utils v0.32.2
-
-replace k8s.io/mount-utils => k8s.io/mount-utils v0.29.3
-
 exclude (
 	// missing tag, referred to by github.com/hashicorp/go-kms-wrapping@v0.5.1
 	github.com/hashicorp/vault/sdk v0.1.14-0.20191229212425-c478d00be0d6
@@ -126,6 +122,7 @@ require (
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/moby/sys/mountinfo v0.7.2 // indirect
+	github.com/moby/sys/userns v0.1.0 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
diff --git a/go.sum b/go.sum
index 9d91eb5b169..eaab2b84034 100644
--- a/go.sum
+++ b/go.sum
@@ -120,8 +120,6 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2
 github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY=
 github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 h1:PZV5W8yk4OtH1JAuhV2PXwwO9v5G5Aoj+eMCn4T+1Kc=
 github.com/aws/aws-sdk-go-v2/service/sts v1.33.17/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4=
-github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ=
-github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
 github.com/aws/smithy-go v1.22.3 h1:Z//5NuZCSW6R4PhQ93hShNbyBbn8BWCmCVCt+Q8Io5k=
 github.com/aws/smithy-go v1.22.3/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
@@ -136,10 +134,6 @@ github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4r
 github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/ceph/go-ceph v0.32.0 h1:iXRUGdPmH7h9Vf/WA1Dg3Wo1tgL7gcUbylfpbxrlGLs=
-github.com/ceph/go-ceph v0.32.0/go.mod h1:42eoJzyLS3VREzqrg2ot44NtuluQZi55hFRSoLF36GQ=
-github.com/ceph/go-ceph v0.32.1-0.20250303071035-7740b94e7f49 h1:0q5Ye65vYS5szvVsH5VILBGTv80p6v+znzPHsjiheDg=
-github.com/ceph/go-ceph v0.32.1-0.20250303071035-7740b94e7f49/go.mod h1:FtN9DMlp/aS7VuO0VXdpdFfaetHNwtvn5q8gIhW/hQ4=
 github.com/ceph/go-ceph v0.32.1-0.20250307053135-38b9676b1d4e h1:Ykum5wAFYzyUi+yW0qQFDsbP9pAuRKTOf+ttMoo1jZ4=
 github.com/ceph/go-ceph v0.32.1-0.20250307053135-38b9676b1d4e/go.mod h1:bIS41nqhGmD7gQVoSBu3IYCwCiVEMeIxFU5qaqmC4a8=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
@@ -511,6 +505,8 @@ github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0Gq
 github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
 github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
 github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
+github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
+github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -731,6 +727,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -1383,8 +1380,8 @@ k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8X
 k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas=
 k8s.io/kubernetes v1.32.2 h1:mShetlA102UpjRVSGzB+5vjJwy8oPy8FMWrkTH5f37o=
 k8s.io/kubernetes v1.32.2/go.mod h1:tiIKO63GcdPRBHW2WiUFm3C0eoLczl3f7qi56Dm1W8I=
-k8s.io/mount-utils v0.29.3 h1:iEcqPP7Vv8UClH8nnMfovtmy/04fIloRW9JuSXykoZ0=
-k8s.io/mount-utils v0.29.3/go.mod h1:9IWJTMe8tG0MYMLEp60xK9GYVeCdA3g4LowmnVi+t9Y=
+k8s.io/mount-utils v0.32.2 h1:aDwp+ucWiVnDr/LpRg88/dsXf/vm6gI1VZkYH3+3+Vw=
+k8s.io/mount-utils v0.32.2/go.mod h1:Kun5c2svjAPx0nnvJKYQWhfeNW+O0EpzHgRhDcYoSY0=
 k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
diff --git a/internal/cephfs/fuserecovery.go b/internal/cephfs/fuserecovery.go
index 41f60aa2a31..398a97cefa6 100644
--- a/internal/cephfs/fuserecovery.go
+++ b/internal/cephfs/fuserecovery.go
@@ -47,7 +47,7 @@ func (ms mountState) String() string {
 }
 
 func (ns *NodeServer) getMountState(path string) (mountState, error) {
-	isMnt, err := util.IsMountPoint(ns.Mounter, path)
+	isMnt, err := ns.Mounter.IsMountPoint(path)
 	if err != nil {
 		if util.IsCorruptedMountError(err) {
 			return msCorrupted, nil
diff --git a/internal/cephfs/nodeserver.go b/internal/cephfs/nodeserver.go
index 2a525e26d85..52d9b39fde0 100644
--- a/internal/cephfs/nodeserver.go
+++ b/internal/cephfs/nodeserver.go
@@ -263,7 +263,7 @@ func (ns *NodeServer) NodeStageVolume(
 		}
 	}
 
-	isMnt, err := util.IsMountPoint(ns.Mounter, stagingTargetPath)
+	isMnt, err := ns.Mounter.IsMountPoint(stagingTargetPath)
 	if err != nil {
 		log.ErrorLog(ctx, "stat failed: %v", err)
 
@@ -539,7 +539,7 @@ func (ns *NodeServer) NodePublishVolume(
 
 	// Ensure staging target path is a mountpoint.
 
-	isMnt, err := util.IsMountPoint(ns.Mounter, stagingTargetPath)
+	isMnt, err := ns.Mounter.IsMountPoint(stagingTargetPath)
 	if err != nil {
 		log.ErrorLog(ctx, "stat failed: %v", err)
 
@@ -552,7 +552,7 @@ func (ns *NodeServer) NodePublishVolume(
 
 	// Check if the volume is already mounted
 
-	isMnt, err = util.IsMountPoint(ns.Mounter, targetPath)
+	isMnt, err = ns.Mounter.IsMountPoint(targetPath)
 	if err != nil {
 		log.ErrorLog(ctx, "stat failed: %v", err)
 
@@ -615,7 +615,7 @@ func (ns *NodeServer) NodeUnpublishVolume(
 	// stop the health-checker that may have been started in NodeGetVolumeStats()
 	ns.healthChecker.StopChecker(volID, targetPath)
 
-	isMnt, err := util.IsMountPoint(ns.Mounter, targetPath)
+	isMnt, err := ns.Mounter.IsMountPoint(targetPath)
 	if err != nil {
 		log.ErrorLog(ctx, "stat failed: %v", err)
 
@@ -687,7 +687,7 @@ func (ns *NodeServer) NodeUnstageVolume(
 		return nil, status.Error(codes.Internal, err.Error())
 	}
 
-	isMnt, err := util.IsMountPoint(ns.Mounter, stagingTargetPath)
+	isMnt, err := ns.Mounter.IsMountPoint(stagingTargetPath)
 	if err != nil {
 		log.ErrorLog(ctx, "stat failed: %v", err)
 
diff --git a/internal/csi-common/utils.go b/internal/csi-common/utils.go
index b541e68f6f4..e9ac2ce6963 100644
--- a/internal/csi-common/utils.go
+++ b/internal/csi-common/utils.go
@@ -25,7 +25,6 @@ import (
 	"sync/atomic"
 	"time"
 
-	"github.com/ceph/ceph-csi/internal/util"
 	"github.com/ceph/ceph-csi/internal/util/log"
 
 	"github.com/container-storage-interface/spec/lib/go/csi"
@@ -351,7 +350,7 @@ func FilesystemNodeGetVolumeStats(
 	targetPath string,
 	includeInodes bool,
 ) (*csi.NodeGetVolumeStatsResponse, error) {
-	isMnt, err := util.IsMountPoint(mounter, targetPath)
+	isMnt, err := mounter.IsMountPoint(targetPath)
 	if err != nil {
 		if os.IsNotExist(err) {
 			return nil, status.Errorf(codes.InvalidArgument, "targetpath %s does not exist", targetPath)
diff --git a/internal/nfs/nodeserver/nodeserver.go b/internal/nfs/nodeserver/nodeserver.go
index 19baaa80ab7..994f6e12ac6 100644
--- a/internal/nfs/nodeserver/nodeserver.go
+++ b/internal/nfs/nodeserver/nodeserver.go
@@ -200,19 +200,19 @@ func (ns *NodeServer) mountNFS(
 		err    error
 	)
 
-	notMnt, err := ns.Mounter.IsLikelyNotMountPoint(mountPoint)
+	isMnt, err := ns.Mounter.IsMountPoint(mountPoint)
 	if err != nil {
 		if os.IsNotExist(err) {
 			err = os.MkdirAll(mountPoint, defaultMountPermission)
 			if err != nil {
 				return err
 			}
-			notMnt = true
+			isMnt = false
 		} else {
 			return err
 		}
 	}
-	if !notMnt {
+	if isMnt {
 		log.DebugLog(ctx, "nfs: volume is already mounted to %s", mountPoint)
 
 		return nil
diff --git a/internal/rbd/nodeserver.go b/internal/rbd/nodeserver.go
index 1522559c6ca..f2a3783a115 100644
--- a/internal/rbd/nodeserver.go
+++ b/internal/rbd/nodeserver.go
@@ -721,12 +721,12 @@ func (ns *NodeServer) NodePublishVolume(
 	defer ns.VolumeLocks.Release(targetPath)
 
 	// Check if that target path exists properly
-	notMnt, err := ns.createTargetMountPath(ctx, targetPath, isBlock)
+	isMnt, err := ns.createTargetMountPath(ctx, targetPath, isBlock)
 	if err != nil {
-		return nil, err
+		return nil, status.Error(codes.Internal, err.Error())
 	}
 
-	if !notMnt {
+	if isMnt {
 		return &csi.NodePublishVolumeResponse{}, nil
 	}
 
@@ -878,37 +878,45 @@ func (ns *NodeServer) mountVolume(ctx context.Context, stagingPath string, req *
 	return nil
 }
 
+// createTargetMountPath check if the mountPath already has something mounted
+// on it. If not, the directory (for a filesystem volume) will be created.
+//
+// This function returns 'true' in case there is something mounted on the given
+// path already, 'false' when the path exists, but nothing is mounted there.
 func (ns *NodeServer) createTargetMountPath(ctx context.Context, mountPath string, isBlock bool) (bool, error) {
-	// Check if that mount path exists properly
-	notMnt, err := ns.Mounter.IsLikelyNotMountPoint(mountPath)
+	isMnt, err := ns.Mounter.IsMountPoint(mountPath)
 	if err == nil {
-		return notMnt, nil
+		return isMnt, nil
 	}
 	if !os.IsNotExist(err) {
-		return false, status.Error(codes.Internal, err.Error())
+		return false, fmt.Errorf("path %q exists, but detecting it as mount point failed: %w", mountPath, err)
 	}
-	if isBlock {
-		// #nosec
-		pathFile, e := os.OpenFile(mountPath, os.O_CREATE|os.O_RDWR, 0o750)
-		if e != nil {
-			log.DebugLog(ctx, "Failed to create mountPath:%s with error: %v", mountPath, err)
 
-			return notMnt, status.Error(codes.Internal, e.Error())
-		}
-		if err = pathFile.Close(); err != nil {
-			log.DebugLog(ctx, "Failed to close mountPath:%s with error: %v", mountPath, err)
-
-			return notMnt, status.Error(codes.Internal, err.Error())
-		}
-	} else {
+	// filesystem volume needs a directory
+	if !isBlock {
 		// Create a mountpath directory
 		if err = util.CreateMountPoint(mountPath); err != nil {
-			return notMnt, status.Error(codes.Internal, err.Error())
+			return false, fmt.Errorf("failed to create mount path %q: %w", mountPath, err)
 		}
+
+		return false, nil
+	}
+
+	// block volume checks
+	// #nosec
+	pathFile, err := os.OpenFile(mountPath, os.O_CREATE|os.O_RDWR, 0o750)
+	if err != nil {
+		log.DebugLog(ctx, "Failed to create mountPath:%s with error: %v", mountPath, err)
+
+		return false, fmt.Errorf("failed to create mount file %q: %w", mountPath, err)
+	}
+	if err = pathFile.Close(); err != nil {
+		log.DebugLog(ctx, "Failed to close mountPath:%s with error: %v", mountPath, err)
+
+		return false, fmt.Errorf("failed to close mount file %q: %w", mountPath, err)
 	}
-	notMnt = true
 
-	return notMnt, err
+	return false, nil
 }
 
 // NodeUnpublishVolume unmounts the volume from the target path.
diff --git a/internal/util/util.go b/internal/util/util.go
index 16f8974d2ba..7c79fd32330 100644
--- a/internal/util/util.go
+++ b/internal/util/util.go
@@ -219,16 +219,6 @@ func checkDirExists(p string) bool {
 	return true
 }
 
-// IsMountPoint checks if the given path is mountpoint or not.
-func IsMountPoint(mounter mount.Interface, p string) (bool, error) {
-	notMnt, err := mounter.IsLikelyNotMountPoint(p)
-	if err != nil {
-		return false, err
-	}
-
-	return !notMnt, nil
-}
-
 // IsCorruptedMountError checks if the given error is a result of a corrupted
 // mountpoint.
 func IsCorruptedMountError(err error) bool {
diff --git a/vendor/github.com/moby/sys/userns/LICENSE b/vendor/github.com/moby/sys/userns/LICENSE
new file mode 100644
index 00000000000..d6456956733
--- /dev/null
+++ b/vendor/github.com/moby/sys/userns/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/vendor/github.com/moby/sys/userns/userns.go b/vendor/github.com/moby/sys/userns/userns.go
new file mode 100644
index 00000000000..56b24c44ad0
--- /dev/null
+++ b/vendor/github.com/moby/sys/userns/userns.go
@@ -0,0 +1,16 @@
+// Package userns provides utilities to detect whether we are currently running
+// in a Linux user namespace.
+//
+// This code was migrated from [libcontainer/runc], which based its implementation
+// on code from [lcx/incus].
+//
+// [libcontainer/runc]: https://github.com/opencontainers/runc/blob/3778ae603c706494fd1e2c2faf83b406e38d687d/libcontainer/userns/userns_linux.go#L12-L49
+// [lcx/incus]: https://github.com/lxc/incus/blob/e45085dd42f826b3c8c3228e9733c0b6f998eafe/shared/util.go#L678-L700
+package userns
+
+// RunningInUserNS detects whether we are currently running in a Linux
+// user namespace and memoizes the result. It returns false on non-Linux
+// platforms.
+func RunningInUserNS() bool {
+	return inUserNS()
+}
diff --git a/vendor/github.com/moby/sys/userns/userns_linux.go b/vendor/github.com/moby/sys/userns/userns_linux.go
new file mode 100644
index 00000000000..87c1c38eec2
--- /dev/null
+++ b/vendor/github.com/moby/sys/userns/userns_linux.go
@@ -0,0 +1,53 @@
+package userns
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"sync"
+)
+
+var inUserNS = sync.OnceValue(runningInUserNS)
+
+// runningInUserNS detects whether we are currently running in a user namespace.
+//
+// This code was migrated from [libcontainer/runc] and based on an implementation
+// from [lcx/incus].
+//
+// [libcontainer/runc]: https://github.com/opencontainers/runc/blob/3778ae603c706494fd1e2c2faf83b406e38d687d/libcontainer/userns/userns_linux.go#L12-L49
+// [lcx/incus]: https://github.com/lxc/incus/blob/e45085dd42f826b3c8c3228e9733c0b6f998eafe/shared/util.go#L678-L700
+func runningInUserNS() bool {
+	file, err := os.Open("/proc/self/uid_map")
+	if err != nil {
+		// This kernel-provided file only exists if user namespaces are supported.
+		return false
+	}
+	defer file.Close()
+
+	buf := bufio.NewReader(file)
+	l, _, err := buf.ReadLine()
+	if err != nil {
+		return false
+	}
+
+	return uidMapInUserNS(string(l))
+}
+
+func uidMapInUserNS(uidMap string) bool {
+	if uidMap == "" {
+		// File exist but empty (the initial state when userns is created,
+		// see user_namespaces(7)).
+		return true
+	}
+
+	var a, b, c int64
+	if _, err := fmt.Sscanf(uidMap, "%d %d %d", &a, &b, &c); err != nil {
+		// Assume we are in a regular, non user namespace.
+		return false
+	}
+
+	// As per user_namespaces(7), /proc/self/uid_map of
+	// the initial user namespace shows 0 0 4294967295.
+	initNS := a == 0 && b == 0 && c == 4294967295
+	return !initNS
+}
diff --git a/vendor/github.com/moby/sys/userns/userns_linux_fuzzer.go b/vendor/github.com/moby/sys/userns/userns_linux_fuzzer.go
new file mode 100644
index 00000000000..26ba2e16ec4
--- /dev/null
+++ b/vendor/github.com/moby/sys/userns/userns_linux_fuzzer.go
@@ -0,0 +1,8 @@
+//go:build linux && gofuzz
+
+package userns
+
+func FuzzUIDMap(uidmap []byte) int {
+	_ = uidMapInUserNS(string(uidmap))
+	return 1
+}
diff --git a/vendor/github.com/moby/sys/userns/userns_unsupported.go b/vendor/github.com/moby/sys/userns/userns_unsupported.go
new file mode 100644
index 00000000000..8ed83072c23
--- /dev/null
+++ b/vendor/github.com/moby/sys/userns/userns_unsupported.go
@@ -0,0 +1,6 @@
+//go:build !linux
+
+package userns
+
+// inUserNS is a stub for non-Linux systems. Always returns false.
+func inUserNS() bool { return false }
diff --git a/vendor/k8s.io/mount-utils/mount_helper_unix.go b/vendor/k8s.io/mount-utils/mount_helper_unix.go
index 9193e7c8d2b..1c603dca7a0 100644
--- a/vendor/k8s.io/mount-utils/mount_helper_unix.go
+++ b/vendor/k8s.io/mount-utils/mount_helper_unix.go
@@ -61,7 +61,13 @@ func IsCorruptedMnt(err error) bool {
 		underlyingError = err
 	}
 
-	return underlyingError == syscall.ENOTCONN || underlyingError == syscall.ESTALE || underlyingError == syscall.EIO || underlyingError == syscall.EACCES || underlyingError == syscall.EHOSTDOWN || underlyingError == syscall.EWOULDBLOCK
+	return errors.Is(underlyingError, syscall.ENOTCONN) ||
+		errors.Is(underlyingError, syscall.ESTALE) ||
+		errors.Is(underlyingError, syscall.EIO) ||
+		errors.Is(underlyingError, syscall.EACCES) ||
+		errors.Is(underlyingError, syscall.EHOSTDOWN) ||
+		errors.Is(underlyingError, syscall.EWOULDBLOCK) ||
+		errors.Is(underlyingError, syscall.ENODEV)
 }
 
 // MountInfo represents a single line in /proc/<pid>/mountinfo.
diff --git a/vendor/k8s.io/mount-utils/mount_linux.go b/vendor/k8s.io/mount-utils/mount_linux.go
index 7d180723047..439d5058941 100644
--- a/vendor/k8s.io/mount-utils/mount_linux.go
+++ b/vendor/k8s.io/mount-utils/mount_linux.go
@@ -33,7 +33,9 @@ import (
 	"time"
 
 	"github.com/moby/sys/mountinfo"
+	"golang.org/x/sys/unix"
 
+	inuserns "github.com/moby/sys/userns"
 	"k8s.io/klog/v2"
 	utilexec "k8s.io/utils/exec"
 )
@@ -55,6 +57,11 @@ const (
 	errNotMounted = "not mounted"
 )
 
+var (
+	// Error statx support since Linux 4.11, https://man7.org/linux/man-pages/man2/statx.2.html
+	errStatxNotSupport = errors.New("the statx syscall is not supported. At least Linux kernel 4.11 is needed")
+)
+
 // Mounter provides the default implementation of mount.Interface
 // for the linux platform.  This implementation assumes that the
 // kubelet is running in the host's root mount namespace.
@@ -105,6 +112,59 @@ func (mounter *Mounter) hasSystemd() bool {
 	return *mounter.withSystemd
 }
 
+// Map unix.Statfs mount flags ro, nodev, noexec, nosuid, noatime, relatime,
+// nodiratime to mount option flag strings.
+func getUserNSBindMountOptions(path string, statfs func(path string, buf *unix.Statfs_t) (err error)) ([]string, error) {
+	var s unix.Statfs_t
+	var mountOpts []string
+	if err := statfs(path, &s); err != nil {
+		return nil, &os.PathError{Op: "statfs", Path: path, Err: err}
+	}
+	flagMapping := map[int]string{
+		unix.MS_RDONLY:     "ro",
+		unix.MS_NODEV:      "nodev",
+		unix.MS_NOEXEC:     "noexec",
+		unix.MS_NOSUID:     "nosuid",
+		unix.MS_NOATIME:    "noatime",
+		unix.MS_RELATIME:   "relatime",
+		unix.MS_NODIRATIME: "nodiratime",
+	}
+	for k, v := range flagMapping {
+		if int(s.Flags)&k == k {
+			mountOpts = append(mountOpts, v)
+		}
+	}
+	return mountOpts, nil
+}
+
+// Do a bind mount including the needed remount for applying the bind opts.
+// If the remount fails and we are running in a user namespace
+// figure out if the source filesystem has the ro, nodev, noexec, nosuid,
+// noatime, relatime or nodiratime flag set and try another remount with the found flags.
+func (mounter *Mounter) bindMountSensitive(mounterPath string, mountCmd string, source string, target string, fstype string, bindOpts []string, bindRemountOpts []string, bindRemountOptsSensitive []string, mountFlags []string, systemdMountRequired bool) error {
+	err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, mountFlags, systemdMountRequired)
+	if err != nil {
+		return err
+	}
+	err = mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, mountFlags, systemdMountRequired)
+	if inuserns.RunningInUserNS() {
+		if err == nil {
+			return nil
+		}
+		// Check if the source has ro, nodev, noexec, nosuid, noatime, relatime,
+		// nodiratime flag...
+		fixMountOpts, err := getUserNSBindMountOptions(source, unix.Statfs)
+		if err != nil {
+			return &os.PathError{Op: "statfs", Path: source, Err: err}
+		}
+		// ... and retry the mount with flags found above.
+		bindRemountOpts = append(bindRemountOpts, fixMountOpts...)
+		return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, mountFlags, systemdMountRequired)
+	} else {
+		return err
+	}
+}
+
 // Mount mounts source to target as fstype with given options. 'source' and 'fstype' must
 // be an empty string in case it's not required, e.g. for remount, or for auto filesystem
 // type, where kernel handles fstype for you. The mount 'options' is a list of options,
@@ -125,11 +185,7 @@ func (mounter *Mounter) MountSensitive(source string, target string, fstype stri
 	mounterPath := ""
 	bind, bindOpts, bindRemountOpts, bindRemountOptsSensitive := MakeBindOptsSensitive(options, sensitiveOptions)
 	if bind {
-		err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd)
-		if err != nil {
-			return err
-		}
-		return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd)
+		return mounter.bindMountSensitive(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOpts, bindRemountOptsSensitive, nil /* mountFlags */, mounter.trySystemd)
 	}
 	// The list of filesystems that require containerized mounter on GCI image cluster
 	fsTypesNeedMounter := map[string]struct{}{
@@ -154,11 +210,7 @@ func (mounter *Mounter) MountSensitiveWithoutSystemdWithMountFlags(source string
 	mounterPath := ""
 	bind, bindOpts, bindRemountOpts, bindRemountOptsSensitive := MakeBindOptsSensitive(options, sensitiveOptions)
 	if bind {
-		err := mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOptsSensitive, mountFlags, false)
-		if err != nil {
-			return err
-		}
-		return mounter.doMount(mounterPath, defaultMountCommand, source, target, fstype, bindRemountOpts, bindRemountOptsSensitive, mountFlags, false)
+		return mounter.bindMountSensitive(mounterPath, defaultMountCommand, source, target, fstype, bindOpts, bindRemountOpts, bindRemountOptsSensitive, mountFlags, false)
 	}
 	// The list of filesystems that require containerized mounter on GCI image cluster
 	fsTypesNeedMounter := map[string]struct{}{
@@ -385,14 +437,20 @@ func (*Mounter) List() ([]MountPoint, error) {
 	return ListProcMounts(procMountsPath)
 }
 
-// IsLikelyNotMountPoint determines if a directory is not a mountpoint.
-// It is fast but not necessarily ALWAYS correct. If the path is in fact
-// a bind mount from one part of a mount to another it will not be detected.
-// It also can not distinguish between mountpoints and symbolic links.
-// mkdir /tmp/a /tmp/b; mount --bind /tmp/a /tmp/b; IsLikelyNotMountPoint("/tmp/b")
-// will return true. When in fact /tmp/b is a mount point. If this situation
-// is of interest to you, don't use this function...
-func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
+func statx(file string) (unix.Statx_t, error) {
+	var stat unix.Statx_t
+	if err := unix.Statx(unix.AT_FDCWD, file, unix.AT_STATX_DONT_SYNC, 0, &stat); err != nil {
+		if err == unix.ENOSYS {
+			return stat, errStatxNotSupport
+		}
+
+		return stat, err
+	}
+
+	return stat, nil
+}
+
+func (mounter *Mounter) isLikelyNotMountPointStat(file string) (bool, error) {
 	stat, err := os.Stat(file)
 	if err != nil {
 		return true, err
@@ -409,6 +467,51 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
 	return true, nil
 }
 
+func (mounter *Mounter) isLikelyNotMountPointStatx(file string) (bool, error) {
+	var stat, rootStat unix.Statx_t
+	var err error
+
+	if stat, err = statx(file); err != nil {
+		return true, err
+	}
+
+	if stat.Attributes_mask != 0 {
+		if stat.Attributes_mask&unix.STATX_ATTR_MOUNT_ROOT != 0 {
+			if stat.Attributes&unix.STATX_ATTR_MOUNT_ROOT != 0 {
+				// file is a mountpoint
+				return false, nil
+			} else {
+				// no need to check rootStat if unix.STATX_ATTR_MOUNT_ROOT supported
+				return true, nil
+			}
+		}
+	}
+
+	root := filepath.Dir(strings.TrimSuffix(file, "/"))
+	if rootStat, err = statx(root); err != nil {
+		return true, err
+	}
+
+	return (stat.Dev_major == rootStat.Dev_major && stat.Dev_minor == rootStat.Dev_minor), nil
+}
+
+// IsLikelyNotMountPoint determines if a directory is not a mountpoint.
+// It is fast but not necessarily ALWAYS correct. If the path is in fact
+// a bind mount from one part of a mount to another it will not be detected.
+// It also can not distinguish between mountpoints and symbolic links.
+// mkdir /tmp/a /tmp/b; mount --bind /tmp/a /tmp/b; IsLikelyNotMountPoint("/tmp/b")
+// will return true. When in fact /tmp/b is a mount point. If this situation
+// is of interest to you, don't use this function...
+func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
+	notMountPoint, err := mounter.isLikelyNotMountPointStatx(file)
+	if errors.Is(err, errStatxNotSupport) {
+		// fall back to isLikelyNotMountPointStat
+		return mounter.isLikelyNotMountPointStat(file)
+	}
+
+	return notMountPoint, err
+}
+
 // CanSafelySkipMountPointCheck relies on the detected behavior of umount when given a target that is not a mount point.
 func (mounter *Mounter) CanSafelySkipMountPointCheck() bool {
 	return mounter.withSafeNotMountedBehavior
@@ -520,7 +623,7 @@ func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target
 			sensitiveOptionsLog := sanitizedOptionsForLogging(options, sensitiveOptions)
 			detailedErr := fmt.Sprintf("format of disk %q failed: type:(%q) target:(%q) options:(%q) errcode:(%v) output:(%v) ", source, fstype, target, sensitiveOptionsLog, err, string(output))
 			klog.Error(detailedErr)
-			return NewMountError(FormatFailed, detailedErr)
+			return NewMountError(FormatFailed, "%s", detailedErr)
 		}
 
 		klog.Infof("Disk successfully formatted (mkfs): %s - %s %s", fstype, source, target)
@@ -528,7 +631,7 @@ func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target
 		if fstype != existingFormat {
 			// Verify that the disk is formatted with filesystem type we are expecting
 			mountErrorValue = FilesystemMismatch
-			klog.Warningf("Configured to mount disk %s as %s but current format is %s, things might break", source, existingFormat, fstype)
+			klog.Warningf("Configured to mount disk %s as %s but current format is %s, things might break", source, fstype, existingFormat)
 		}
 
 		if !readOnly {
@@ -543,7 +646,7 @@ func (mounter *SafeFormatAndMount) formatAndMountSensitive(source string, target
 	// Mount the disk
 	klog.V(4).Infof("Attempting to mount disk %s in %s format at %s", source, fstype, target)
 	if err := mounter.MountSensitive(source, target, fstype, options, sensitiveOptions); err != nil {
-		return NewMountError(mountErrorValue, err.Error())
+		return NewMountError(mountErrorValue, "%s", err.Error())
 	}
 
 	return nil
diff --git a/vendor/k8s.io/mount-utils/mount_windows.go b/vendor/k8s.io/mount-utils/mount_windows.go
index be714646ec1..9c8ad054f8a 100644
--- a/vendor/k8s.io/mount-utils/mount_windows.go
+++ b/vendor/k8s.io/mount-utils/mount_windows.go
@@ -164,7 +164,7 @@ func (mounter *Mounter) MountSensitive(source string, target string, fstype stri
 // return (output, error)
 func newSMBMapping(username, password, remotepath string) (string, error) {
 	if username == "" || password == "" || remotepath == "" {
-		return "", fmt.Errorf("invalid parameter(username: %s, password: %s, remoteapth: %s)", username, sensitiveOptionsRemoved, remotepath)
+		return "", fmt.Errorf("invalid parameter(username: %s, password: %s, remotepath: %s)", username, sensitiveOptionsRemoved, remotepath)
 	}
 
 	// use PowerShell Environment Variables to store user input string to prevent command line injection
@@ -193,8 +193,8 @@ func isSMBMappingExist(remotepath string) bool {
 // check whether remotepath is valid
 // return (true, nil) if remotepath is valid
 func isValidPath(remotepath string) (bool, error) {
-	cmd := exec.Command("powershell", "/c", `Test-Path $Env:remoteapth`)
-	cmd.Env = append(os.Environ(), fmt.Sprintf("remoteapth=%s", remotepath))
+	cmd := exec.Command("powershell", "/c", `Test-Path $Env:remotepath`)
+	cmd.Env = append(os.Environ(), fmt.Sprintf("remotepath=%s", remotepath))
 	output, err := cmd.CombinedOutput()
 	if err != nil {
 		return false, fmt.Errorf("returned output: %s, error: %v", string(output), err)
diff --git a/vendor/modules.txt b/vendor/modules.txt
index b63461aa25d..5b11d5acf20 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -432,6 +432,9 @@ github.com/mitchellh/mapstructure
 # github.com/moby/sys/mountinfo v0.7.2
 ## explicit; go 1.17
 github.com/moby/sys/mountinfo
+# github.com/moby/sys/userns v0.1.0
+## explicit; go 1.21
+github.com/moby/sys/userns
 # github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
 ## explicit
 github.com/modern-go/concurrent
@@ -1167,8 +1170,8 @@ k8s.io/kubernetes/pkg/volume/util/hostutil
 k8s.io/kubernetes/pkg/volume/util/recyclerclient
 k8s.io/kubernetes/pkg/volume/util/subpath
 k8s.io/kubernetes/pkg/volume/util/types
-# k8s.io/mount-utils v0.32.2 => k8s.io/mount-utils v0.29.3
-## explicit; go 1.21
+# k8s.io/mount-utils v0.32.2
+## explicit; go 1.23.0
 k8s.io/mount-utils
 # k8s.io/utils v0.0.0-20241210054802-24370beab758
 ## explicit; go 1.18
@@ -1244,4 +1247,3 @@ sigs.k8s.io/yaml
 sigs.k8s.io/yaml/goyaml.v2
 # github.com/ceph/ceph-csi/api => ./api
 # k8s.io/client-go => k8s.io/client-go v0.32.2
-# k8s.io/mount-utils => k8s.io/mount-utils v0.29.3


Reviews:
user: login: Madhu-1
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-03-12T08:16:26Z
user: login: nixpanic
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T08:54:38Z
user: login: nixpanic
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T12:07:18Z
user: login: Madhu-1
body: LGTM, if possible please see if you can address the nits. 
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-13T09:17:36Z
user: login: nixpanic
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T09:37:28Z
user: login: nixpanic
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-13T12:30:33Z
user: login: Madhu-1
body: LGTM
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-13T13:22:04Z
user: login: iPraveenParihar
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T06:26:06Z

Review comments:
diff_hunk: @@ -200,7 +200,7 @@ func (ns *NodeServer) mountNFS(
 		err    error
 	)
 
-	notMnt, err := ns.Mounter.IsLikelyNotMountPoint(mountPoint)
+	notMnt, err := ns.Mounter.IsMountPoint(mountPoint)
path: internal/nfs/nodeserver/nodeserver.go
user: login: Madhu-1
body: we should change `notMnt` to `Ismnt` or something like that and we should reverse the check for it because `IsLikelyNotMountPoint` was returning its a mount point or not as `!` operation of IsMountPoint
created_at: 2025-03-12T08:15:34Z
author_association: COLLABORATOR
diff_hunk: @@ -200,7 +200,7 @@ func (ns *NodeServer) mountNFS(
 		err    error
 	)
 
-	notMnt, err := ns.Mounter.IsLikelyNotMountPoint(mountPoint)
+	notMnt, err := ns.Mounter.IsMountPoint(mountPoint)
path: internal/nfs/nodeserver/nodeserver.go
user: login: nixpanic
body: Ah, yes :facepalm: 
created_at: 2025-03-12T08:54:38Z
author_association: MEMBER
diff_hunk: @@ -200,7 +200,7 @@ func (ns *NodeServer) mountNFS(
 		err    error
 	)
 
-	notMnt, err := ns.Mounter.IsLikelyNotMountPoint(mountPoint)
+	notMnt, err := ns.Mounter.IsMountPoint(mountPoint)
path: internal/nfs/nodeserver/nodeserver.go
user: login: nixpanic
body: This should have been addressed now. Thanks for catching!
created_at: 2025-03-12T12:07:18Z
author_association: MEMBER
diff_hunk: @@ -200,19 +200,19 @@ func (ns *NodeServer) mountNFS(
 		err    error
 	)
 
-	notMnt, err := ns.Mounter.IsLikelyNotMountPoint(mountPoint)
+	isMnt, err := ns.Mounter.IsMountPoint(mountPoint)
 	if err != nil {
 		if os.IsNotExist(err) {
 			err = os.MkdirAll(mountPoint, defaultMountPermission)
 			if err != nil {
 				return err
 			}
-			notMnt = true
+			isMnt = false
path: internal/nfs/nodeserver/nodeserver.go
user: login: Madhu-1
body: i think this check is not required, because of an error, isMnt will be set to false by default
created_at: 2025-03-13T09:14:29Z
author_association: COLLABORATOR
diff_hunk: @@ -880,9 +880,9 @@ func (ns *NodeServer) mountVolume(ctx context.Context, stagingPath string, req *
 
 func (ns *NodeServer) createTargetMountPath(ctx context.Context, mountPath string, isBlock bool) (bool, error) {
path: internal/rbd/nodeserver.go
user: login: Madhu-1
body: can we update the `createTargetMountPath` to return isMnt to check it simple, returning `!` and doing `!` check on the function return value looks so confusing :( 
created_at: 2025-03-13T09:17:15Z
author_association: COLLABORATOR
diff_hunk: @@ -880,9 +880,9 @@ func (ns *NodeServer) mountVolume(ctx context.Context, stagingPath string, req *
 
 func (ns *NodeServer) createTargetMountPath(ctx context.Context, mountPath string, isBlock bool) (bool, error) {
path: internal/rbd/nodeserver.go
user: login: nixpanic
body: Sure, I can clean that up. It confused me a little too.
created_at: 2025-03-13T09:37:28Z
author_association: MEMBER
diff_hunk: @@ -880,9 +880,9 @@ func (ns *NodeServer) mountVolume(ctx context.Context, stagingPath string, req *
 
 func (ns *NodeServer) createTargetMountPath(ctx context.Context, mountPath string, isBlock bool) (bool, error) {
path: internal/rbd/nodeserver.go
user: login: nixpanic
body: @Madhu-1 , please have an other look. The 2nd commit simplifies `createTargetMountPath()`.
created_at: 2025-03-13T12:30:33Z
author_association: MEMBER

PR comments:
user: login: iPraveenParihar
created_at: 2025-03-07T16:18:44Z
body: /test ci/centos/mini-e2e-helm/k8s-1.32
author_association: CONTRIBUTOR
user: login: Madhu-1
created_at: 2025-03-10T10:53:42Z
body: /test ci/centos/mini-e2e-helm/k8s-1.31
author_association: COLLABORATOR
user: login: Madhu-1
created_at: 2025-03-10T10:57:49Z
body: @nixpanic we are using `IsLikelyNotMountPoint` in two other places (nfs,rbd) can we replace it as well?
author_association: COLLABORATOR
user: login: nixpanic
created_at: 2025-03-11T08:32:07Z
body: > @nixpanic we are using `IsLikelyNotMountPoint` in two other places (nfs,rbd) can we replace it as well?

Sure, done!
author_association: MEMBER
user: login: nixpanic
created_at: 2025-03-11T15:05:33Z
body: /test ci/centos/mini-e2e-helm/k8s-1.32
author_association: MEMBER
user: login: iPraveenParihar
created_at: 2025-03-14T04:44:42Z
body: /test ci/centos/mini-e2e-helm/k8s-1.32
author_association: CONTRIBUTOR
user: login: Rakshith-R
created_at: 2025-03-14T08:26:13Z
body: @mergifyio queue 
author_association: CONTRIBUTOR
user: login: mergify[bot]
created_at: 2025-03-14T08:26:20Z
body: > queue

#### ✅ The pull request has been merged automatically

<details>

The pull request has been merged automatically at *7f7988be0d7df257ed0bcb2a882a2e1e2759c0c6*

</details>


<!---
DO NOT EDIT
-*- Mergify Payload -*-
{"command": "queue", "conclusion": "success", "action_is_running": true}
-*- Mergify Payload End -*-
-->
author_association: CONTRIBUTOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:16Z
body: /test ci/centos/upgrade-tests-cephfs
author_association: COLLABORATOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:17Z
body: /test ci/centos/upgrade-tests-rbd
author_association: COLLABORATOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:17Z
body: /test ci/centos/k8s-e2e-external-storage/1.30
author_association: COLLABORATOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:17Z
body: /test ci/centos/mini-e2e-helm/k8s-1.30
author_association: COLLABORATOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:18Z
body: /test ci/centos/mini-e2e/k8s-1.30
author_association: COLLABORATOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:18Z
body: /test ci/centos/k8s-e2e-external-storage/1.32
author_association: COLLABORATOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:18Z
body: /test ci/centos/k8s-e2e-external-storage/1.31
author_association: COLLABORATOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:19Z
body: /test ci/centos/mini-e2e-helm/k8s-1.32
author_association: COLLABORATOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:19Z
body: /test ci/centos/mini-e2e-helm/k8s-1.31
author_association: COLLABORATOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:19Z
body: /test ci/centos/mini-e2e/k8s-1.32
author_association: COLLABORATOR
user: login: ceph-csi-bot
created_at: 2025-03-14T08:32:20Z
body: /test ci/centos/mini-e2e/k8s-1.31
author_association: COLLABORATOR