|
@@ -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
|
|
|
+}
|