Skip to content

Commit

Permalink
mountinfo.Mounted: optimize by adding fast paths
Browse files Browse the repository at this point in the history
Add two fast paths to avoid (slow) mountinfo parsing:

1. In case path does not exist, it is definitely NOT a mount point.

2. In case path's st.Dev differs from that of its parent, it is
   definitely a mount point.

In all the other cases (including bind mounts, case of path="/", other
errors from unix.Lstat) the code falls back to the old slow method
of parsing mountinfo.

Signed-off-by: Kir Kolyshkin <[email protected]>
  • Loading branch information
kolyshkin committed Jun 30, 2020
1 parent 9e8d3ad commit 2ebd59a
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 12 deletions.
2 changes: 2 additions & 0 deletions mountinfo/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/moby/sys/mountinfo

go 1.14

require golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae
2 changes: 2 additions & 0 deletions mountinfo/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
16 changes: 5 additions & 11 deletions mountinfo/mountinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,13 @@ func GetMountsFromReader(reader io.Reader, f FilterFunc) ([]*Info, error) {
return parseInfoFile(reader, f)
}

// Mounted determines if a specified mountpoint has been mounted.
// On Linux it looks at /proc/self/mountinfo.
// Mounted determines if a specified path is a mount point.
//
// The argument must be an absolute path, with all symlinks resolved, and clean.
// One way to ensure it is to process the path using filepath.EvalSymlinks before
// calling this function.
func Mounted(mountpoint string) (bool, error) {
entries, err := GetMounts(SingleEntryFilter(mountpoint))
if err != nil {
return false, err
}

return len(entries) > 0, nil
// One way to ensure it is to process the path using filepath.Abs followed by
// filepath.EvalSymlinks before calling this function.
func Mounted(path string) (bool, error) {
return mounted(path)
}

// Info reveals information about a particular mounted filesystem. This
Expand Down
35 changes: 35 additions & 0 deletions mountinfo/mountinfo_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// +build !windows

package mountinfo

import (
"path/filepath"

"golang.org/x/sys/unix"
)

func mounted(path string) (bool, error) {
var st unix.Stat_t

err := unix.Lstat(path, &st)
switch err {
case unix.ENOENT:
// Nonexistent path, so not a mount point.
return false, nil
case nil:
dev := st.Dev
err = unix.Lstat(filepath.Dir(path), &st)
if err == nil && dev != st.Dev {
// Device number differs from that of parent,
// so definitely a mount point.
return true, nil
}
}

entries, err := GetMounts(SingleEntryFilter(path))
if err != nil {
return false, err
}

return len(entries) > 0, nil
}
8 changes: 7 additions & 1 deletion mountinfo/mountinfo_unsupported.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@ import (
"runtime"
)

var errNotImplemented = fmt.Errorf("not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)

func parseMountTable(_ FilterFunc) ([]*Info, error) {
return nil, fmt.Errorf("mount.parseMountTable is not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
return nil, errNotImplemented
}

func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
return parseMountTable(f)
}

func mounted(path string) (bool, error) {
return false, errNotImplemented
}
4 changes: 4 additions & 0 deletions mountinfo/mountinfo_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ func parseMountTable(_ FilterFunc) ([]*Info, error) {
func parseInfoFile(_ io.Reader, f FilterFunc) ([]*Info, error) {
return parseMountTable(f)
}

func mounted(_ string) (bool, error) {
return false, nil
}

0 comments on commit 2ebd59a

Please sign in to comment.