apply_raw.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. package fs
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. "strconv"
  8. "github.com/dotcloud/docker/pkg/libcontainer/cgroups"
  9. )
  10. var (
  11. subsystems = map[string]subsystem{
  12. "devices": &devicesGroup{},
  13. "memory": &memoryGroup{},
  14. "cpu": &cpuGroup{},
  15. "cpuset": &cpusetGroup{},
  16. "cpuacct": &cpuacctGroup{},
  17. "blkio": &blkioGroup{},
  18. "perf_event": &perfEventGroup{},
  19. "freezer": &freezerGroup{},
  20. }
  21. )
  22. type subsystem interface {
  23. Set(*data) error
  24. Remove(*data) error
  25. GetStats(*data, *cgroups.Stats) error
  26. }
  27. type data struct {
  28. root string
  29. cgroup string
  30. c *cgroups.Cgroup
  31. pid int
  32. }
  33. func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
  34. d, err := getCgroupData(c, pid)
  35. if err != nil {
  36. return nil, err
  37. }
  38. for _, sys := range subsystems {
  39. if err := sys.Set(d); err != nil {
  40. d.Cleanup()
  41. return nil, err
  42. }
  43. }
  44. return d, nil
  45. }
  46. func GetStats(c *cgroups.Cgroup) (*cgroups.Stats, error) {
  47. stats := cgroups.NewStats()
  48. d, err := getCgroupData(c, 0)
  49. if err != nil {
  50. return nil, err
  51. }
  52. for _, sys := range subsystems {
  53. if err := sys.GetStats(d, stats); err != nil {
  54. return nil, err
  55. }
  56. }
  57. return stats, nil
  58. }
  59. // Freeze toggles the container's freezer cgroup depending on the state
  60. // provided
  61. func Freeze(c *cgroups.Cgroup, state cgroups.FreezerState) error {
  62. d, err := getCgroupData(c, 0)
  63. if err != nil {
  64. return err
  65. }
  66. c.Freezer = state
  67. freezer := subsystems["freezer"]
  68. return freezer.Set(d)
  69. }
  70. func GetPids(c *cgroups.Cgroup) ([]int, error) {
  71. d, err := getCgroupData(c, 0)
  72. if err != nil {
  73. return nil, err
  74. }
  75. dir, err := d.path("devices")
  76. if err != nil {
  77. return nil, err
  78. }
  79. return cgroups.ReadProcsFile(dir)
  80. }
  81. func getCgroupData(c *cgroups.Cgroup, pid int) (*data, error) {
  82. // we can pick any subsystem to find the root
  83. cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu")
  84. if err != nil {
  85. return nil, err
  86. }
  87. cgroupRoot = filepath.Dir(cgroupRoot)
  88. if _, err := os.Stat(cgroupRoot); err != nil {
  89. return nil, fmt.Errorf("cgroups fs not found")
  90. }
  91. cgroup := c.Name
  92. if c.Parent != "" {
  93. cgroup = filepath.Join(c.Parent, cgroup)
  94. }
  95. return &data{
  96. root: cgroupRoot,
  97. cgroup: cgroup,
  98. c: c,
  99. pid: pid,
  100. }, nil
  101. }
  102. func (raw *data) parent(subsystem string) (string, error) {
  103. initPath, err := cgroups.GetInitCgroupDir(subsystem)
  104. if err != nil {
  105. return "", err
  106. }
  107. return filepath.Join(raw.root, subsystem, initPath), nil
  108. }
  109. func (raw *data) path(subsystem string) (string, error) {
  110. parent, err := raw.parent(subsystem)
  111. if err != nil {
  112. return "", err
  113. }
  114. return filepath.Join(parent, raw.cgroup), nil
  115. }
  116. func (raw *data) join(subsystem string) (string, error) {
  117. path, err := raw.path(subsystem)
  118. if err != nil {
  119. return "", err
  120. }
  121. if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
  122. return "", err
  123. }
  124. if err := writeFile(path, "cgroup.procs", strconv.Itoa(raw.pid)); err != nil {
  125. return "", err
  126. }
  127. return path, nil
  128. }
  129. func (raw *data) Cleanup() error {
  130. for _, sys := range subsystems {
  131. sys.Remove(raw)
  132. }
  133. return nil
  134. }
  135. func writeFile(dir, file, data string) error {
  136. return ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700)
  137. }
  138. func readFile(dir, file string) (string, error) {
  139. data, err := ioutil.ReadFile(filepath.Join(dir, file))
  140. return string(data), err
  141. }
  142. func removePath(p string, err error) error {
  143. if err != nil {
  144. return err
  145. }
  146. if p != "" {
  147. return os.RemoveAll(p)
  148. }
  149. return nil
  150. }