mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 10:53:34 +00:00
util: do not use mount-utils.IsLikelyNotMountPoint
anymore
`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 Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
committed by
mergify[bot]
parent
76b4f53897
commit
79cf0321dd
26
e2e/go.mod
26
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
|
||||
|
@ -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=
|
||||
|
8
e2e/vendor/k8s.io/mount-utils/mount_helper_unix.go
generated
vendored
8
e2e/vendor/k8s.io/mount-utils/mount_helper_unix.go
generated
vendored
@ -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.
|
||||
|
145
e2e/vendor/k8s.io/mount-utils/mount_linux.go
generated
vendored
145
e2e/vendor/k8s.io/mount-utils/mount_linux.go
generated
vendored
@ -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
|
||||
|
6
e2e/vendor/k8s.io/mount-utils/mount_windows.go
generated
vendored
6
e2e/vendor/k8s.io/mount-utils/mount_windows.go
generated
vendored
@ -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)
|
||||
|
5
e2e/vendor/modules.txt
vendored
5
e2e/vendor/modules.txt
vendored
@ -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
|
||||
|
Reference in New Issue
Block a user