1
16
17 package cgroups
18
19 import (
20 "bytes"
21 "fmt"
22 "os"
23 "path/filepath"
24
25 specs "github.com/opencontainers/runtime-spec/specs-go"
26 )
27
28 func NewCpuset(root string) *cpusetController {
29 return &cpusetController{
30 root: filepath.Join(root, string(Cpuset)),
31 }
32 }
33
34 type cpusetController struct {
35 root string
36 }
37
38 func (c *cpusetController) Name() Name {
39 return Cpuset
40 }
41
42 func (c *cpusetController) Path(path string) string {
43 return filepath.Join(c.root, path)
44 }
45
46 func (c *cpusetController) Create(path string, resources *specs.LinuxResources) error {
47 if err := c.ensureParent(c.Path(path), c.root); err != nil {
48 return err
49 }
50 if err := os.MkdirAll(c.Path(path), defaultDirPerm); err != nil {
51 return err
52 }
53 if err := c.copyIfNeeded(c.Path(path), filepath.Dir(c.Path(path))); err != nil {
54 return err
55 }
56 if resources.CPU != nil {
57 for _, t := range []struct {
58 name string
59 value string
60 }{
61 {
62 name: "cpus",
63 value: resources.CPU.Cpus,
64 },
65 {
66 name: "mems",
67 value: resources.CPU.Mems,
68 },
69 } {
70 if t.value != "" {
71 if err := retryingWriteFile(
72 filepath.Join(c.Path(path), "cpuset."+t.name),
73 []byte(t.value),
74 defaultFilePerm,
75 ); err != nil {
76 return err
77 }
78 }
79 }
80 }
81 return nil
82 }
83
84 func (c *cpusetController) Update(path string, resources *specs.LinuxResources) error {
85 return c.Create(path, resources)
86 }
87
88 func (c *cpusetController) getValues(path string) (cpus []byte, mems []byte, err error) {
89 if cpus, err = os.ReadFile(filepath.Join(path, "cpuset.cpus")); err != nil && !os.IsNotExist(err) {
90 return
91 }
92 if mems, err = os.ReadFile(filepath.Join(path, "cpuset.mems")); err != nil && !os.IsNotExist(err) {
93 return
94 }
95 return cpus, mems, nil
96 }
97
98
99
100
101 func (c *cpusetController) ensureParent(current, root string) error {
102 parent := filepath.Dir(current)
103 if _, err := filepath.Rel(root, parent); err != nil {
104 return nil
105 }
106
107 if parent == current {
108 return fmt.Errorf("cpuset: cgroup parent path outside cgroup root")
109 }
110 if cleanPath(parent) != root {
111 if err := c.ensureParent(parent, root); err != nil {
112 return err
113 }
114 }
115 if err := os.MkdirAll(current, defaultDirPerm); err != nil {
116 return err
117 }
118 return c.copyIfNeeded(current, parent)
119 }
120
121
122
123 func (c *cpusetController) copyIfNeeded(current, parent string) error {
124 var (
125 err error
126 currentCpus, currentMems []byte
127 parentCpus, parentMems []byte
128 )
129 if currentCpus, currentMems, err = c.getValues(current); err != nil {
130 return err
131 }
132 if parentCpus, parentMems, err = c.getValues(parent); err != nil {
133 return err
134 }
135 if isEmpty(currentCpus) {
136 if err := retryingWriteFile(
137 filepath.Join(current, "cpuset.cpus"),
138 parentCpus,
139 defaultFilePerm,
140 ); err != nil {
141 return err
142 }
143 }
144 if isEmpty(currentMems) {
145 if err := retryingWriteFile(
146 filepath.Join(current, "cpuset.mems"),
147 parentMems,
148 defaultFilePerm,
149 ); err != nil {
150 return err
151 }
152 }
153 return nil
154 }
155
156 func isEmpty(b []byte) bool {
157 return len(bytes.Trim(b, "\n")) == 0
158 }
159
View as plain text