diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index 5bb61d5fe1..4a0779b116 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -1694,51 +1694,32 @@ func setupOOMScoreAdj(score int) error { return err } -func (daemon *Daemon) initCgroupsPath(path string) error { +func (daemon *Daemon) initCPURtController(mnt, path string) error { if path == "/" || path == "." { return nil } - if daemon.configStore.CPURealtimePeriod == 0 && daemon.configStore.CPURealtimeRuntime == 0 { - return nil - } - - if cgroups.IsCgroup2UnifiedMode() { - return fmt.Errorf("daemon-scoped cpu-rt-period and cpu-rt-runtime are not implemented for cgroup v2") - } - // Recursively create cgroup to ensure that the system and all parent cgroups have values set // for the period and runtime as this limits what the children can be set to. - daemon.initCgroupsPath(filepath.Dir(path)) - - mnt, root, err := cgroups.FindCgroupMountpointAndRoot("", "cpu") - if err != nil { + if err := daemon.initCPURtController(mnt, filepath.Dir(path)); err != nil { return err } - // When docker is run inside docker, the root is based of the host cgroup. - // Should this be handled in runc/libcontainer/cgroups ? - if strings.HasPrefix(root, "/docker/") { - root = "/" - } - path = filepath.Join(mnt, root, path) - sysInfo := daemon.RawSysInfo(true) - if err := maybeCreateCPURealTimeFile(sysInfo.CPURealtime, daemon.configStore.CPURealtimePeriod, "cpu.rt_period_us", path); err != nil { + path = filepath.Join(mnt, path) + if err := os.MkdirAll(path, 0755); err != nil { return err } - return maybeCreateCPURealTimeFile(sysInfo.CPURealtime, daemon.configStore.CPURealtimeRuntime, "cpu.rt_runtime_us", path) + if err := maybeCreateCPURealTimeFile(daemon.configStore.CPURealtimePeriod, "cpu.rt_period_us", path); err != nil { + return err + } + return maybeCreateCPURealTimeFile(daemon.configStore.CPURealtimeRuntime, "cpu.rt_runtime_us", path) } -func maybeCreateCPURealTimeFile(sysinfoPresent bool, configValue int64, file string, path string) error { - if sysinfoPresent && configValue != 0 { - if err := os.MkdirAll(path, 0755); err != nil { - return err - } - if err := ioutil.WriteFile(filepath.Join(path, file), []byte(strconv.FormatInt(configValue, 10)), 0700); err != nil { - return err - } +func maybeCreateCPURealTimeFile(configValue int64, file string, path string) error { + if configValue == 0 { + return nil } - return nil + return ioutil.WriteFile(filepath.Join(path, file), []byte(strconv.FormatInt(configValue, 10)), 0700) } func (daemon *Daemon) setupSeccompProfile() error { diff --git a/daemon/oci_linux.go b/daemon/oci_linux.go index da1de47470..180cd4e992 100644 --- a/daemon/oci_linux.go +++ b/daemon/oci_linux.go @@ -824,15 +824,32 @@ func WithCgroups(daemon *Daemon, c *container.Container) coci.SpecOpts { cgroupsPath = filepath.Join(parent, c.ID) } s.Linux.CgroupsPath = cgroupsPath + + // the rest is only needed for CPU RT controller + + if daemon.configStore.CPURealtimePeriod == 0 && daemon.configStore.CPURealtimeRuntime == 0 { + return nil + } + + if cgroups.IsCgroup2UnifiedMode() { + return errors.New("daemon-scoped cpu-rt-period and cpu-rt-runtime are not implemented for cgroup v2") + } + + // FIXME this is very expensive way to check if cpu rt is supported + sysInfo := daemon.RawSysInfo(true) + if !sysInfo.CPURealtime { + return errors.New("daemon-scoped cpu-rt-period and cpu-rt-runtime are not supported by the kernel") + } + p := cgroupsPath if useSystemd { initPath, err := cgroups.GetInitCgroup("cpu") if err != nil { - return err + return errors.Wrap(err, "unable to init CPU RT controller") } _, err = cgroups.GetOwnCgroup("cpu") if err != nil { - return err + return errors.Wrap(err, "unable to init CPU RT controller") } p = filepath.Join(initPath, s.Linux.CgroupsPath) } @@ -843,8 +860,19 @@ func WithCgroups(daemon *Daemon, c *container.Container) coci.SpecOpts { parentPath = filepath.Clean("/" + parentPath) } - if err := daemon.initCgroupsPath(parentPath); err != nil { - return fmt.Errorf("linux init cgroups path: %v", err) + mnt, root, err := cgroups.FindCgroupMountpointAndRoot("", "cpu") + if err != nil { + return errors.Wrap(err, "unable to init CPU RT controller") + } + // When docker is run inside docker, the root is based of the host cgroup. + // Should this be handled in runc/libcontainer/cgroups ? + if strings.HasPrefix(root, "/docker/") { + root = "/" + } + mnt = filepath.Join(mnt, root) + + if err := daemon.initCPURtController(mnt, parentPath); err != nil { + return errors.Wrap(err, "unable to init CPU RT controller") } return nil }