@@ -29,10 +29,10 @@ import (
29
29
"path/filepath"
30
30
"strconv"
31
31
"strings"
32
- "syscall"
33
32
"time"
34
33
35
34
"github.com/moby/sys/mountinfo"
35
+ "golang.org/x/sys/unix"
36
36
37
37
"k8s.io/klog/v2"
38
38
utilexec "k8s.io/utils/exec"
@@ -385,28 +385,55 @@ func (*Mounter) List() ([]MountPoint, error) {
385
385
return ListProcMounts (procMountsPath )
386
386
}
387
387
388
+ // statx support since Linux 4.11, glibc 2.28
389
+ // refer: https://man7.org/linux/man-pages/man2/statx.2.html
390
+ var errNotSupport = errors .New ("The statx syscall is not supported. At least Linux kernel 4.11 is needed" )
391
+
392
+ func statx (file string ) (unix.Statx_t , error ) {
393
+ var stat unix.Statx_t
394
+ if err := unix .Statx (0 , file , unix .AT_STATX_DONT_SYNC , 0 , & stat ); err != nil {
395
+ if err == unix .ENOSYS {
396
+ return stat , errNotSupport
397
+ }
398
+
399
+ return stat , err
400
+ }
401
+
402
+ return stat , nil
403
+ }
404
+
388
405
// 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.
406
+ // If fast check failed, fall back to slow path . If the path is in fact
407
+ // a bind mount from one part of a mount to another it will be detected.
408
+ // It also can distinguish between mountpoints and symbolic links.
392
409
// 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...
410
+ // will return false. When in fact /tmp/b is a mount point.
411
+
412
+ // TODO(j4ckstraw) add test
395
413
func (mounter * Mounter ) IsLikelyNotMountPoint (file string ) (bool , error ) {
396
- stat , err := os .Stat (file )
397
- if err != nil {
398
- return true , err
399
- }
400
- rootStat , err := os .Stat (filepath .Dir (strings .TrimSuffix (file , "/" )))
401
- if err != nil {
402
- return true , err
414
+ var stat , rootStat unix.Statx_t
415
+ var err error
416
+
417
+ if stat , err = statx (file ); err != nil {
418
+ if errors .Is (err , errNotSupport ) {
419
+ // not support statx, go slow path
420
+ mnt , mntErr := mounter .IsMountPoint (file )
421
+ return ! mnt , mntErr
422
+ }
423
+
424
+ return false , err
403
425
}
404
- // If the directory has a different device as parent, then it is a mountpoint.
405
- if stat .Sys ().(* syscall.Stat_t ).Dev != rootStat .Sys ().(* syscall.Stat_t ).Dev {
406
- return false , nil
426
+
427
+ root := filepath .Dir (strings .TrimSuffix (file , "/" ))
428
+ if rootStat , err = statx (root ); err != nil {
429
+ return false , err
407
430
}
408
431
409
- return true , nil
432
+ // TODO add STATX_ATTR_MOUNT_ROOT support, which can check mountpoint correctly.
433
+ // Linux 5.8 commit 80340fe3605c0e78cfe496c3b3878be828cfdbfe
434
+ // stat->attributes |= STATX_ATTR_MOUNT_ROOT;
435
+ // stat->attributes_mask |= STATX_ATTR_MOUNT_ROOT;
436
+ return ! (stat .Dev_major == rootStat .Dev_major && stat .Dev_minor == rootStat .Dev_minor ), nil
410
437
}
411
438
412
439
// CanSafelySkipMountPointCheck relies on the detected behavior of umount when given a target that is not a mount point.
0 commit comments