summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKir Kolyshkin <kolyshkin@gmail.com>2020-03-31 01:59:44 -0700
committerKir Kolyshkin <kolyshkin@gmail.com>2020-04-02 07:52:34 -0700
commite0614367ca27c2e47649e08291e0f1d19d42232e (patch)
tree8eeb95dd01fc5bed27cd08ffc61244950bed7d56
parentf2c42a3958d12b45375aeb2384a3a8a103203c1c (diff)
downloadpodman-e0614367ca27c2e47649e08291e0f1d19d42232e.tar.gz
podman-e0614367ca27c2e47649e08291e0f1d19d42232e.tar.bz2
podman-e0614367ca27c2e47649e08291e0f1d19d42232e.zip
pkg/spec.InitFSMounts: optimize
Instead of getting mount options from /proc/self/mountinfo, which is very costly to read/parse (and can even be unreliable), let's use statfs(2) to figure out the flags we need. [v2: move getting default options to pkg/util, make it linux-specific] Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
-rw-r--r--libpod/options.go2
-rw-r--r--pkg/spec/storage.go60
-rw-r--r--pkg/util/mountOpts.go24
-rw-r--r--pkg/util/mountOpts_linux.go23
-rw-r--r--pkg/util/mountOpts_other.go7
5 files changed, 49 insertions, 67 deletions
diff --git a/libpod/options.go b/libpod/options.go
index dfbec364a..65a089131 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -1334,7 +1334,7 @@ func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption {
}
destinations[vol.Dest] = true
- mountOpts, err := util.ProcessOptions(vol.Options, false, nil)
+ mountOpts, err := util.ProcessOptions(vol.Options, false, "")
if err != nil {
return errors.Wrapf(err, "error processing options for named volume %q mounted at %q", vol.Name, vol.Dest)
}
diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go
index 335907d12..68a84d638 100644
--- a/pkg/spec/storage.go
+++ b/pkg/spec/storage.go
@@ -10,7 +10,6 @@ import (
"github.com/containers/buildah/pkg/parse"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/util"
- pmount "github.com/containers/storage/pkg/mount"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -856,44 +855,16 @@ func SupercedeUserMounts(mounts []spec.Mount, configMount []spec.Mount) []spec.M
// Ensure mount options on all mounts are correct
func InitFSMounts(mounts []spec.Mount) error {
- // We need to look up mounts so we can figure out the proper mount flags
- // to apply.
- systemMounts, err := pmount.GetMounts()
- if err != nil {
- return errors.Wrapf(err, "error retrieving system mounts to look up mount options")
- }
-
for i, m := range mounts {
- if m.Type == TypeBind {
- baseMnt, err := findMount(m.Source, systemMounts)
- if err != nil {
- return errors.Wrapf(err, "error looking up mountpoint for mount %s", m.Source)
- }
- var noexec, nosuid, nodev bool
- for _, baseOpt := range strings.Split(baseMnt.Opts, ",") {
- switch baseOpt {
- case "noexec":
- noexec = true
- case "nosuid":
- nosuid = true
- case "nodev":
- nodev = true
- }
- }
-
- defaultMountOpts := new(util.DefaultMountOptions)
- defaultMountOpts.Noexec = noexec
- defaultMountOpts.Nosuid = nosuid
- defaultMountOpts.Nodev = nodev
-
- opts, err := util.ProcessOptions(m.Options, false, defaultMountOpts)
+ switch {
+ case m.Type == TypeBind:
+ opts, err := util.ProcessOptions(m.Options, false, m.Source)
if err != nil {
return err
}
mounts[i].Options = opts
- }
- if m.Type == TypeTmpfs && filepath.Clean(m.Destination) != "/dev" {
- opts, err := util.ProcessOptions(m.Options, true, nil)
+ case m.Type == TypeTmpfs && filepath.Clean(m.Destination) != "/dev":
+ opts, err := util.ProcessOptions(m.Options, true, "")
if err != nil {
return err
}
@@ -902,24 +873,3 @@ func InitFSMounts(mounts []spec.Mount) error {
}
return nil
}
-
-// TODO: We could make this a bit faster by building a tree of the mountpoints
-// and traversing it to identify the correct mount.
-func findMount(target string, mounts []*pmount.Info) (*pmount.Info, error) {
- var err error
- target, err = filepath.Abs(target)
- if err != nil {
- return nil, errors.Wrapf(err, "cannot resolve %s", target)
- }
- var bestSoFar *pmount.Info
- for _, i := range mounts {
- if bestSoFar != nil && len(bestSoFar.Mountpoint) > len(i.Mountpoint) {
- // Won't be better than what we have already found
- continue
- }
- if strings.HasPrefix(target, i.Mountpoint) {
- bestSoFar = i
- }
- }
- return bestSoFar, nil
-}
diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go
index d21800bc3..329a7c913 100644
--- a/pkg/util/mountOpts.go
+++ b/pkg/util/mountOpts.go
@@ -13,19 +13,17 @@ var (
ErrDupeMntOption = errors.Errorf("duplicate mount option passed")
)
-// DefaultMountOptions sets default mount options for ProcessOptions.
-type DefaultMountOptions struct {
- Noexec bool
- Nosuid bool
- Nodev bool
+type defaultMountOptions struct {
+ noexec bool
+ nosuid bool
+ nodev bool
}
// ProcessOptions parses the options for a bind or tmpfs mount and ensures that
// they are sensible and follow convention. The isTmpfs variable controls
// whether extra, tmpfs-specific options will be allowed.
-// The defaults variable controls default mount options that will be set. If it
-// is not included, they will be set unconditionally.
-func ProcessOptions(options []string, isTmpfs bool, defaults *DefaultMountOptions) ([]string, error) {
+// The sourcePath variable, if not empty, contains a bind mount source.
+func ProcessOptions(options []string, isTmpfs bool, sourcePath string) ([]string, error) {
var (
foundWrite, foundSize, foundProp, foundMode, foundExec, foundSuid, foundDev, foundCopyUp, foundBind, foundZ bool
)
@@ -122,13 +120,17 @@ func ProcessOptions(options []string, isTmpfs bool, defaults *DefaultMountOption
if !foundProp {
newOptions = append(newOptions, "rprivate")
}
- if !foundExec && (defaults == nil || defaults.Noexec) {
+ defaults, err := getDefaultMountOptions(sourcePath)
+ if err != nil {
+ return nil, err
+ }
+ if !foundExec && defaults.noexec {
newOptions = append(newOptions, "noexec")
}
- if !foundSuid && (defaults == nil || defaults.Nosuid) {
+ if !foundSuid && defaults.nosuid {
newOptions = append(newOptions, "nosuid")
}
- if !foundDev && (defaults == nil || defaults.Nodev) {
+ if !foundDev && defaults.nodev {
newOptions = append(newOptions, "nodev")
}
if isTmpfs && !foundCopyUp {
diff --git a/pkg/util/mountOpts_linux.go b/pkg/util/mountOpts_linux.go
new file mode 100644
index 000000000..3eac4dd25
--- /dev/null
+++ b/pkg/util/mountOpts_linux.go
@@ -0,0 +1,23 @@
+package util
+
+import (
+ "os"
+
+ "golang.org/x/sys/unix"
+)
+
+func getDefaultMountOptions(path string) (defaultMountOptions, error) {
+ opts := defaultMountOptions{true, true, true}
+ if path == "" {
+ return opts, nil
+ }
+ var statfs unix.Statfs_t
+ if e := unix.Statfs(path, &statfs); e != nil {
+ return opts, &os.PathError{Op: "statfs", Path: path, Err: e}
+ }
+ opts.nodev = (statfs.Flags&unix.MS_NODEV == unix.MS_NODEV)
+ opts.noexec = (statfs.Flags&unix.MS_NOEXEC == unix.MS_NOEXEC)
+ opts.nosuid = (statfs.Flags&unix.MS_NOSUID == unix.MS_NOSUID)
+
+ return opts, nil
+}
diff --git a/pkg/util/mountOpts_other.go b/pkg/util/mountOpts_other.go
new file mode 100644
index 000000000..6a34942e5
--- /dev/null
+++ b/pkg/util/mountOpts_other.go
@@ -0,0 +1,7 @@
+// +build !linux
+
+package util
+
+func getDefaultMountOptions(path string) (opts defaultMountOptions, err error) {
+ return
+}