@@ -33,6 +33,7 @@ import (
33
33
"time"
34
34
35
35
"github.com/moby/sys/mountinfo"
36
+ "golang.org/x/sys/unix"
36
37
37
38
"k8s.io/klog/v2"
38
39
utilexec "k8s.io/utils/exec"
@@ -55,6 +56,11 @@ const (
55
56
errNotMounted = "not mounted"
56
57
)
57
58
59
+ var (
60
+ // Error statx support since Linux 4.11, https://man7.org/linux/man-pages/man2/statx.2.html
61
+ errStatxNotSupport = errors .New ("the statx syscall is not supported. At least Linux kernel 4.11 is needed" )
62
+ )
63
+
58
64
// Mounter provides the default implementation of mount.Interface
59
65
// for the linux platform. This implementation assumes that the
60
66
// kubelet is running in the host's root mount namespace.
@@ -385,14 +391,20 @@ func (*Mounter) List() ([]MountPoint, error) {
385
391
return ListProcMounts (procMountsPath )
386
392
}
387
393
388
- // IsLikelyNotMountPoint determines if a directory is not a mountpoint.
389
- // It is fast but not necessarily ALWAYS correct. If the path is in fact
390
- // a bind mount from one part of a mount to another it will not be detected.
391
- // It also can not distinguish between mountpoints and symbolic links.
392
- // mkdir /tmp/a /tmp/b; mount --bind /tmp/a /tmp/b; IsLikelyNotMountPoint("/tmp/b")
393
- // will return true. When in fact /tmp/b is a mount point. If this situation
394
- // is of interest to you, don't use this function...
395
- func (mounter * Mounter ) IsLikelyNotMountPoint (file string ) (bool , error ) {
394
+ func statx (file string ) (unix.Statx_t , error ) {
395
+ var stat unix.Statx_t
396
+ if err := unix .Statx (0 , file , unix .AT_STATX_DONT_SYNC , 0 , & stat ); err != nil {
397
+ if err == unix .ENOSYS {
398
+ return stat , errStatxNotSupport
399
+ }
400
+
401
+ return stat , err
402
+ }
403
+
404
+ return stat , nil
405
+ }
406
+
407
+ func (mounter * Mounter ) isLikelyNotMountPointStat (file string ) (bool , error ) {
396
408
stat , err := os .Stat (file )
397
409
if err != nil {
398
410
return true , err
@@ -409,6 +421,51 @@ func (mounter *Mounter) IsLikelyNotMountPoint(file string) (bool, error) {
409
421
return true , nil
410
422
}
411
423
424
+ func (mounter * Mounter ) isLikelyNotMountPointStatx (file string ) (bool , error ) {
425
+ var stat , rootStat unix.Statx_t
426
+ var err error
427
+
428
+ if stat , err = statx (file ); err != nil {
429
+ return true , err
430
+ }
431
+
432
+ if stat .Attributes_mask != 0 {
433
+ if stat .Attributes_mask & unix .STATX_ATTR_MOUNT_ROOT != 0 {
434
+ if stat .Attributes & unix .STATX_ATTR_MOUNT_ROOT != 0 {
435
+ // file is a mountpoint
436
+ return false , nil
437
+ } else {
438
+ // no need to check rootStat if unix.STATX_ATTR_MOUNT_ROOT supported
439
+ return true , nil
440
+ }
441
+ }
442
+ }
443
+
444
+ root := filepath .Dir (strings .TrimSuffix (file , "/" ))
445
+ if rootStat , err = statx (root ); err != nil {
446
+ return true , err
447
+ }
448
+
449
+ return (stat .Dev_major == rootStat .Dev_major && stat .Dev_minor == rootStat .Dev_minor ), nil
450
+ }
451
+
452
+ // IsLikelyNotMountPoint determines if a directory is not a mountpoint.
453
+ // It is fast but not necessarily ALWAYS correct. If the path is in fact
454
+ // a bind mount from one part of a mount to another it will not be detected.
455
+ // It also can not distinguish between mountpoints and symbolic links.
456
+ // mkdir /tmp/a /tmp/b; mount --bind /tmp/a /tmp/b; IsLikelyNotMountPoint("/tmp/b")
457
+ // will return true. When in fact /tmp/b is a mount point. If this situation
458
+ // is of interest to you, don't use this function...
459
+ func (mounter * Mounter ) IsLikelyNotMountPoint (file string ) (bool , error ) {
460
+ notMountPoint , err := mounter .isLikelyNotMountPointStatx (file )
461
+ if errors .Is (err , errStatxNotSupport ) {
462
+ // fall back to isLikelyNotMountPointStat
463
+ return mounter .isLikelyNotMountPointStat (file )
464
+ }
465
+
466
+ return notMountPoint , err
467
+ }
468
+
412
469
// CanSafelySkipMountPointCheck relies on the detected behavior of umount when given a target that is not a mount point.
413
470
func (mounter * Mounter ) CanSafelySkipMountPointCheck () bool {
414
471
return mounter .withSafeNotMountedBehavior
0 commit comments