From 3de15bda7e1d3ab193094e6e07a5b2e42ea828bd Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Tue, 13 May 2014 13:34:31 -0700 Subject: [PATCH] Copy parents cpus and mems for cpuset Docker-DCO-1.1-Signed-off-by: Michael Crosby (github: crosbymichael) --- pkg/cgroups/fs/apply_raw.go | 12 +++++- pkg/cgroups/fs/cpuset.go | 86 ++++++++++++++++++++++++++++++++++--- 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/pkg/cgroups/fs/apply_raw.go b/pkg/cgroups/fs/apply_raw.go index 5f9fc826b3..ee26bffac5 100644 --- a/pkg/cgroups/fs/apply_raw.go +++ b/pkg/cgroups/fs/apply_raw.go @@ -103,12 +103,20 @@ func GetStats(c *cgroups.Cgroup, subsystem string, pid int) (map[string]float64, return sys.Stats(d) } -func (raw *data) path(subsystem string) (string, error) { +func (raw *data) parent(subsystem string) (string, error) { initPath, err := cgroups.GetInitCgroupDir(subsystem) if err != nil { return "", err } - return filepath.Join(raw.root, subsystem, initPath, raw.cgroup), nil + return filepath.Join(raw.root, subsystem, initPath), nil +} + +func (raw *data) path(subsystem string) (string, error) { + parent, err := raw.parent(subsystem) + if err != nil { + return "", err + } + return filepath.Join(parent, raw.cgroup), nil } func (raw *data) join(subsystem string) (string, error) { diff --git a/pkg/cgroups/fs/cpuset.go b/pkg/cgroups/fs/cpuset.go index 8a13c56cea..f9f65ba422 100644 --- a/pkg/cgroups/fs/cpuset.go +++ b/pkg/cgroups/fs/cpuset.go @@ -1,7 +1,11 @@ package fs import ( + "bytes" + "io/ioutil" "os" + "path/filepath" + "strconv" ) type cpusetGroup struct { @@ -10,16 +14,19 @@ type cpusetGroup struct { func (s *cpusetGroup) Set(d *data) error { // we don't want to join this cgroup unless it is specified if d.c.CpusetCpus != "" { - dir, err := d.join("cpuset") - if err != nil && d.c.CpusetCpus != "" { + dir, err := d.path("cpuset") + if err != nil { + return err + } + if err := s.ensureParent(dir); err != nil { return err } - defer func() { - if err != nil { - os.RemoveAll(dir) - } - }() + // because we are not using d.join we need to place the pid into the procs file + // unlike the other subsystems + if err := writeFile(dir, "cgroup.procs", strconv.Itoa(d.pid)); err != nil { + return err + } if err := writeFile(dir, "cpuset.cpus", d.c.CpusetCpus); err != nil { return err } @@ -34,3 +41,68 @@ func (s *cpusetGroup) Remove(d *data) error { func (s *cpusetGroup) Stats(d *data) (map[string]float64, error) { return nil, ErrNotSupportStat } + +func (s *cpusetGroup) getSubsystemSettings(parent string) (cpus []byte, mems []byte, err error) { + if cpus, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.cpus")); err != nil { + return + } + if mems, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.mems")); err != nil { + return + } + return cpus, mems, nil +} + +// ensureParent ensures that the parent directory of current is created +// with the proper cpus and mems files copied from it's parent if the values +// are a file with a new line char +func (s *cpusetGroup) ensureParent(current string) error { + parent := filepath.Dir(current) + + if _, err := os.Stat(parent); err != nil { + if !os.IsNotExist(err) { + return err + } + + if err := s.ensureParent(parent); err != nil { + return err + } + } + + if err := os.MkdirAll(current, 0755); err != nil && !os.IsExist(err) { + return err + } + return s.copyIfNeeded(current, parent) +} + +// copyIfNeeded copies the cpuset.cpus and cpuset.mems from the parent +// directory to the current directory if the file's contents are 0 +func (s *cpusetGroup) copyIfNeeded(current, parent string) error { + var ( + err error + currentCpus, currentMems []byte + parentCpus, parentMems []byte + ) + + if currentCpus, currentMems, err = s.getSubsystemSettings(current); err != nil { + return err + } + if parentCpus, parentMems, err = s.getSubsystemSettings(parent); err != nil { + return err + } + + if s.isEmpty(currentCpus) { + if err := writeFile(current, "cpuset.cpus", string(parentCpus)); err != nil { + return err + } + } + if s.isEmpty(currentMems) { + if err := writeFile(current, "cpuset.mems", string(parentMems)); err != nil { + return err + } + } + return nil +} + +func (s *cpusetGroup) isEmpty(b []byte) bool { + return len(bytes.Trim(b, "\n")) == 0 +}