cgroup/fs: rework Apply()
In manager.Apply() method, a path to each subsystem is obtained by calling d.path(sys.Name()), and the sys.Apply() is called that does the same call to d.path() again. d.path() is an expensive call, so rather than to call it twice, let's reuse the result. This results the number of times we parse mountinfo during container start from 62 to 34 on my setup. Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
parent
819fcc687e
commit
c1adc99a20
|
@ -22,12 +22,8 @@ func (s *BlkioGroup) Name() string {
|
||||||
return "blkio"
|
return "blkio"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BlkioGroup) Apply(d *cgroupData) error {
|
func (s *BlkioGroup) Apply(path string, d *cgroupData) error {
|
||||||
_, err := d.join("blkio")
|
return join(path, d.pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error {
|
func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
|
@ -21,17 +21,7 @@ func (s *CpuGroup) Name() string {
|
||||||
return "cpu"
|
return "cpu"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CpuGroup) Apply(d *cgroupData) error {
|
func (s *CpuGroup) Apply(path string, d *cgroupData) error {
|
||||||
// We always want to join the cpu group, to allow fair cpu scheduling
|
|
||||||
// on a container basis
|
|
||||||
path, err := d.path("cpu")
|
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return s.ApplyDir(path, d.config, d.pid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CpuGroup) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error {
|
|
||||||
// This might happen if we have no cpu cgroup mounted.
|
// This might happen if we have no cpu cgroup mounted.
|
||||||
// Just do nothing and don't fail.
|
// Just do nothing and don't fail.
|
||||||
if path == "" {
|
if path == "" {
|
||||||
|
@ -43,12 +33,12 @@ func (s *CpuGroup) ApplyDir(path string, cgroup *configs.Cgroup, pid int) error
|
||||||
// We should set the real-Time group scheduling settings before moving
|
// We should set the real-Time group scheduling settings before moving
|
||||||
// in the process because if the process is already in SCHED_RR mode
|
// in the process because if the process is already in SCHED_RR mode
|
||||||
// and no RT bandwidth is set, adding it will fail.
|
// and no RT bandwidth is set, adding it will fail.
|
||||||
if err := s.SetRtSched(path, cgroup); err != nil {
|
if err := s.SetRtSched(path, d.config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// because we are not using d.join we need to place the pid into the procs file
|
// Since we are not using join(), we need to place the pid
|
||||||
// unlike the other subsystems
|
// into the procs file unlike other subsystems.
|
||||||
return cgroups.WriteCgroupProc(path, pid)
|
return cgroups.WriteCgroupProc(path, d.pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CpuGroup) SetRtSched(path string, cgroup *configs.Cgroup) error {
|
func (s *CpuGroup) SetRtSched(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
|
@ -182,7 +182,9 @@ func TestCpuSetRtSchedAtApply(t *testing.T) {
|
||||||
helper.CgroupData.config.Resources.CpuRtRuntime = rtRuntimeAfter
|
helper.CgroupData.config.Resources.CpuRtRuntime = rtRuntimeAfter
|
||||||
helper.CgroupData.config.Resources.CpuRtPeriod = rtPeriodAfter
|
helper.CgroupData.config.Resources.CpuRtPeriod = rtPeriodAfter
|
||||||
cpu := &CpuGroup{}
|
cpu := &CpuGroup{}
|
||||||
if err := cpu.ApplyDir(helper.CgroupPath, helper.CgroupData.config, 1234); err != nil {
|
|
||||||
|
helper.CgroupData.pid = 1234
|
||||||
|
if err := cpu.Apply(helper.CgroupPath, helper.CgroupData); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,8 @@ func (s *CpuacctGroup) Name() string {
|
||||||
return "cpuacct"
|
return "cpuacct"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CpuacctGroup) Apply(d *cgroupData) error {
|
func (s *CpuacctGroup) Apply(path string, d *cgroupData) error {
|
||||||
// we just want to join this group even though we don't set anything
|
return join(path, d.pid)
|
||||||
if _, err := d.join("cpuacct"); err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CpuacctGroup) Set(path string, cgroup *configs.Cgroup) error {
|
func (s *CpuacctGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
|
@ -23,12 +23,8 @@ func (s *CpusetGroup) Name() string {
|
||||||
return "cpuset"
|
return "cpuset"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CpusetGroup) Apply(d *cgroupData) error {
|
func (s *CpusetGroup) Apply(path string, d *cgroupData) error {
|
||||||
dir, err := d.path("cpuset")
|
return s.ApplyDir(path, d.config, d.pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return s.ApplyDir(dir, d.config, d.pid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *CpusetGroup) Set(path string, cgroup *configs.Cgroup) error {
|
func (s *CpusetGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
|
@ -22,17 +22,16 @@ func (s *DevicesGroup) Name() string {
|
||||||
return "devices"
|
return "devices"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DevicesGroup) Apply(d *cgroupData) error {
|
func (s *DevicesGroup) Apply(path string, d *cgroupData) error {
|
||||||
if d.config.SkipDevices {
|
if d.config.SkipDevices {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
_, err := d.join("devices")
|
if path == "" {
|
||||||
if err != nil {
|
// Return error here, since devices cgroup
|
||||||
// We will return error even it's `not found` error, devices
|
// is a hard requirement for container's security.
|
||||||
// cgroup is hard requirement for container's security.
|
return errSubsystemDoesNotExist
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
return nil
|
return join(path, d.pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadEmulator(path string) (*devices.Emulator, error) {
|
func loadEmulator(path string) (*devices.Emulator, error) {
|
||||||
|
|
|
@ -22,12 +22,8 @@ func (s *FreezerGroup) Name() string {
|
||||||
return "freezer"
|
return "freezer"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FreezerGroup) Apply(d *cgroupData) error {
|
func (s *FreezerGroup) Apply(path string, d *cgroupData) error {
|
||||||
_, err := d.join("freezer")
|
return join(path, d.pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error {
|
func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
|
@ -57,7 +57,7 @@ type subsystem interface {
|
||||||
// Removes the cgroup represented by 'cgroupData'.
|
// Removes the cgroup represented by 'cgroupData'.
|
||||||
Remove(*cgroupData) error
|
Remove(*cgroupData) error
|
||||||
// Creates and joins the cgroup represented by 'cgroupData'.
|
// Creates and joins the cgroup represented by 'cgroupData'.
|
||||||
Apply(*cgroupData) error
|
Apply(path string, c *cgroupData) error
|
||||||
// Set the cgroup represented by cgroup.
|
// Set the cgroup represented by cgroup.
|
||||||
Set(path string, cgroup *configs.Cgroup) error
|
Set(path string, cgroup *configs.Cgroup) error
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ func (m *manager) Apply(pid int) (err error) {
|
||||||
}
|
}
|
||||||
m.paths[sys.Name()] = p
|
m.paths[sys.Name()] = p
|
||||||
|
|
||||||
if err := sys.Apply(d); err != nil {
|
if err := sys.Apply(p, d); err != nil {
|
||||||
// In the case of rootless (including euid=0 in userns), where an
|
// In the case of rootless (including euid=0 in userns), where an
|
||||||
// explicit cgroup path hasn't been set, we don't bail on error in
|
// explicit cgroup path hasn't been set, we don't bail on error in
|
||||||
// case of permission problems. Cases where limits have been set
|
// case of permission problems. Cases where limits have been set
|
||||||
|
@ -374,18 +374,14 @@ func (raw *cgroupData) path(subsystem string) (string, error) {
|
||||||
return filepath.Join(parentPath, raw.innerPath), nil
|
return filepath.Join(parentPath, raw.innerPath), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (raw *cgroupData) join(subsystem string) (string, error) {
|
func join(path string, pid int) error {
|
||||||
path, err := raw.path(subsystem)
|
if path == "" {
|
||||||
if err != nil {
|
return nil
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
if err := os.MkdirAll(path, 0755); err != nil {
|
if err := os.MkdirAll(path, 0755); err != nil {
|
||||||
return "", err
|
return err
|
||||||
}
|
}
|
||||||
if err := cgroups.WriteCgroupProc(path, raw.pid); err != nil {
|
return cgroups.WriteCgroupProc(path, pid)
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return path, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func removePath(p string, err error) error {
|
func removePath(p string, err error) error {
|
||||||
|
|
|
@ -19,12 +19,8 @@ func (s *HugetlbGroup) Name() string {
|
||||||
return "hugetlb"
|
return "hugetlb"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HugetlbGroup) Apply(d *cgroupData) error {
|
func (s *HugetlbGroup) Apply(path string, d *cgroupData) error {
|
||||||
_, err := d.join("hugetlb")
|
return join(path, d.pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *HugetlbGroup) Set(path string, cgroup *configs.Cgroup) error {
|
func (s *HugetlbGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
|
@ -37,11 +37,8 @@ func (s *MemoryGroup) Name() string {
|
||||||
return "memory"
|
return "memory"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
|
func (s *MemoryGroup) Apply(path string, d *cgroupData) (err error) {
|
||||||
path, err := d.path("memory")
|
if path == "" {
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
} else if path == "" {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if memoryAssigned(d.config) {
|
if memoryAssigned(d.config) {
|
||||||
|
@ -66,11 +63,7 @@ func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
|
||||||
|
|
||||||
// We need to join memory cgroup after set memory limits, because
|
// We need to join memory cgroup after set memory limits, because
|
||||||
// kmem.limit_in_bytes can only be set when the cgroup is empty.
|
// kmem.limit_in_bytes can only be set when the cgroup is empty.
|
||||||
_, err = d.join("memory")
|
return join(path, d.pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setMemoryAndSwap(path string, cgroup *configs.Cgroup) error {
|
func setMemoryAndSwap(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
|
@ -16,10 +16,10 @@ func (s *NameGroup) Name() string {
|
||||||
return s.GroupName
|
return s.GroupName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NameGroup) Apply(d *cgroupData) error {
|
func (s *NameGroup) Apply(path string, d *cgroupData) error {
|
||||||
if s.Join {
|
if s.Join {
|
||||||
// ignore errors if the named cgroup does not exist
|
// ignore errors if the named cgroup does not exist
|
||||||
d.join(s.GroupName)
|
join(path, d.pid)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,8 @@ func (s *NetClsGroup) Name() string {
|
||||||
return "net_cls"
|
return "net_cls"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NetClsGroup) Apply(d *cgroupData) error {
|
func (s *NetClsGroup) Apply(path string, d *cgroupData) error {
|
||||||
_, err := d.join("net_cls")
|
return join(path, d.pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NetClsGroup) Set(path string, cgroup *configs.Cgroup) error {
|
func (s *NetClsGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
|
@ -15,12 +15,8 @@ func (s *NetPrioGroup) Name() string {
|
||||||
return "net_prio"
|
return "net_prio"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NetPrioGroup) Apply(d *cgroupData) error {
|
func (s *NetPrioGroup) Apply(path string, d *cgroupData) error {
|
||||||
_, err := d.join("net_prio")
|
return join(path, d.pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *NetPrioGroup) Set(path string, cgroup *configs.Cgroup) error {
|
func (s *NetPrioGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
|
@ -14,12 +14,8 @@ func (s *PerfEventGroup) Name() string {
|
||||||
return "perf_event"
|
return "perf_event"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PerfEventGroup) Apply(d *cgroupData) error {
|
func (s *PerfEventGroup) Apply(path string, d *cgroupData) error {
|
||||||
// we just want to join this group even though we don't set anything
|
return join(path, d.pid)
|
||||||
if _, err := d.join("perf_event"); err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PerfEventGroup) Set(path string, cgroup *configs.Cgroup) error {
|
func (s *PerfEventGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
|
@ -19,12 +19,8 @@ func (s *PidsGroup) Name() string {
|
||||||
return "pids"
|
return "pids"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PidsGroup) Apply(d *cgroupData) error {
|
func (s *PidsGroup) Apply(path string, d *cgroupData) error {
|
||||||
_, err := d.join("pids")
|
return join(path, d.pid)
|
||||||
if err != nil && !cgroups.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PidsGroup) Set(path string, cgroup *configs.Cgroup) error {
|
func (s *PidsGroup) Set(path string, cgroup *configs.Cgroup) error {
|
||||||
|
|
Loading…
Reference in New Issue