cpuset.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // +build linux
  2. package fs
  3. import (
  4. "bytes"
  5. "fmt"
  6. "io/ioutil"
  7. "os"
  8. "path/filepath"
  9. "strconv"
  10. "github.com/opencontainers/runc/libcontainer/cgroups"
  11. "github.com/opencontainers/runc/libcontainer/configs"
  12. libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils"
  13. )
  14. type CpusetGroup struct {
  15. }
  16. func (s *CpusetGroup) Name() string {
  17. return "cpuset"
  18. }
  19. func (s *CpusetGroup) Apply(d *cgroupData) error {
  20. dir, err := d.path("cpuset")
  21. if err != nil && !cgroups.IsNotFound(err) {
  22. return err
  23. }
  24. return s.ApplyDir(dir, d.config, d.pid)
  25. }
  26. func (s *CpusetGroup) Set(path string, cgroup *configs.Cgroup) error {
  27. if cgroup.Resources.CpusetCpus != "" {
  28. if err := writeFile(path, "cpuset.cpus", cgroup.Resources.CpusetCpus); err != nil {
  29. return err
  30. }
  31. }
  32. if cgroup.Resources.CpusetMems != "" {
  33. if err := writeFile(path, "cpuset.mems", cgroup.Resources.CpusetMems); err != nil {
  34. return err
  35. }
  36. }
  37. return nil
  38. }
  39. func (s *CpusetGroup) Remove(d *cgroupData) error {
  40. return removePath(d.path("cpuset"))
  41. }
  42. func (s *CpusetGroup) GetStats(path string, stats *cgroups.Stats) error {
  43. return nil
  44. }
  45. func (s *CpusetGroup) ApplyDir(dir string, cgroup *configs.Cgroup, pid int) error {
  46. // This might happen if we have no cpuset cgroup mounted.
  47. // Just do nothing and don't fail.
  48. if dir == "" {
  49. return nil
  50. }
  51. root, err := getCgroupRoot()
  52. if err != nil {
  53. return err
  54. }
  55. if err := s.ensureParent(dir, root); err != nil {
  56. return err
  57. }
  58. // because we are not using d.join we need to place the pid into the procs file
  59. // unlike the other subsystems
  60. if err := writeFile(dir, "cgroup.procs", strconv.Itoa(pid)); err != nil {
  61. return err
  62. }
  63. return nil
  64. }
  65. func (s *CpusetGroup) getSubsystemSettings(parent string) (cpus []byte, mems []byte, err error) {
  66. if cpus, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.cpus")); err != nil {
  67. return
  68. }
  69. if mems, err = ioutil.ReadFile(filepath.Join(parent, "cpuset.mems")); err != nil {
  70. return
  71. }
  72. return cpus, mems, nil
  73. }
  74. // ensureParent makes sure that the parent directory of current is created
  75. // and populated with the proper cpus and mems files copied from
  76. // it's parent.
  77. func (s *CpusetGroup) ensureParent(current, root string) error {
  78. parent := filepath.Dir(current)
  79. if libcontainerUtils.CleanPath(parent) == root {
  80. return nil
  81. }
  82. // Avoid infinite recursion.
  83. if parent == current {
  84. return fmt.Errorf("cpuset: cgroup parent path outside cgroup root")
  85. }
  86. if err := s.ensureParent(parent, root); err != nil {
  87. return err
  88. }
  89. if err := os.MkdirAll(current, 0755); err != nil {
  90. return err
  91. }
  92. return s.copyIfNeeded(current, parent)
  93. }
  94. // copyIfNeeded copies the cpuset.cpus and cpuset.mems from the parent
  95. // directory to the current directory if the file's contents are 0
  96. func (s *CpusetGroup) copyIfNeeded(current, parent string) error {
  97. var (
  98. err error
  99. currentCpus, currentMems []byte
  100. parentCpus, parentMems []byte
  101. )
  102. if currentCpus, currentMems, err = s.getSubsystemSettings(current); err != nil {
  103. return err
  104. }
  105. if parentCpus, parentMems, err = s.getSubsystemSettings(parent); err != nil {
  106. return err
  107. }
  108. if s.isEmpty(currentCpus) {
  109. if err := writeFile(current, "cpuset.cpus", string(parentCpus)); err != nil {
  110. return err
  111. }
  112. }
  113. if s.isEmpty(currentMems) {
  114. if err := writeFile(current, "cpuset.mems", string(parentMems)); err != nil {
  115. return err
  116. }
  117. }
  118. return nil
  119. }
  120. func (s *CpusetGroup) isEmpty(b []byte) bool {
  121. return len(bytes.Trim(b, "\n")) == 0
  122. }