From 079295c02a9d9e0f5d732b60d1f4e0cd0bc6e4e6 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Sat, 16 Nov 2019 04:08:28 +0900 Subject: [PATCH 1/2] v2: refactor ListControllers Signed-off-by: Akihiro Suda --- cmd/cgctl/main.go | 23 ++++++++++++++++++++++- v2/manager.go | 25 ++++++++++--------------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/cmd/cgctl/main.go b/cmd/cgctl/main.go index 545ecf0b..98be1d05 100644 --- a/cmd/cgctl/main.go +++ b/cmd/cgctl/main.go @@ -46,6 +46,7 @@ func main() { newCommand, delCommand, listCommand, + listControllersCommand, statCommand, } app.Before = func(clix *cli.Context) error { @@ -76,7 +77,7 @@ var newCommand = cli.Command{ return err } if clix.Bool("enable") { - controllers, err := c.ListControllers() + controllers, err := c.RootControllers() if err != nil { return err } @@ -121,6 +122,26 @@ var listCommand = cli.Command{ }, } +var listControllersCommand = cli.Command{ + Name: "list-controllers", + Usage: "list controllers in a cgroup", + Action: func(clix *cli.Context) error { + path := clix.Args().First() + c, err := v2.LoadManager(clix.GlobalString("mountpoint"), path) + if err != nil { + return err + } + controllers, err := c.Controllers() + if err != nil { + return err + } + for _, c := range controllers { + fmt.Println(c) + } + return nil + }, +} + var statCommand = cli.Command{ Name: "stat", Usage: "stat a cgroup", diff --git a/v2/manager.go b/v2/manager.go index 021b52ce..945fa4da 100644 --- a/v2/manager.go +++ b/v2/manager.go @@ -168,25 +168,20 @@ func setResources(path string, resources *Resources) error { return nil } -func (c *Manager) ListControllers() ([]string, error) { - f, err := os.Open(filepath.Join(c.path, controllersFile)) +func (c *Manager) RootControllers() ([]string, error) { + b, err := ioutil.ReadFile(filepath.Join(c.unifiedMountpoint, controllersFile)) if err != nil { return nil, err } - defer f.Close() + return strings.Fields(string(b)), nil +} - var ( - out []string - s = bufio.NewScanner(f) - ) - s.Split(bufio.ScanWords) - for s.Scan() { - if err := s.Err(); err != nil { - return nil, err - } - out = append(out, s.Text()) +func (c *Manager) Controllers() ([]string, error) { + b, err := ioutil.ReadFile(filepath.Join(c.path, controllersFile)) + if err != nil { + return nil, err } - return out, nil + return strings.Fields(string(b)), nil } type ControllerToggle int @@ -283,7 +278,7 @@ var singleValueFiles = []string{ } func (c *Manager) Stat() (*stats.Metrics, error) { - controllers, err := c.ListControllers() + controllers, err := c.Controllers() if err != nil { return nil, err } From 302259114275aad7b19c605335603d8285d8851b Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Sat, 16 Nov 2019 04:30:58 +0900 Subject: [PATCH 2/2] v2: toggle ancestors of c.path, not c.path itself Fix #121 Signed-off-by: Akihiro Suda --- v2/manager.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/v2/manager.go b/v2/manager.go index 945fa4da..01fbe600 100644 --- a/v2/manager.go +++ b/v2/manager.go @@ -200,7 +200,31 @@ func toggleFunc(controllers []string, prefix string) []string { } func (c *Manager) ToggleControllers(controllers []string, t ControllerToggle) error { - f, err := os.OpenFile(filepath.Join(c.path, subtreeControl), os.O_WRONLY, 0) + // when c.path is like /foo/bar/baz, the following files need to be written: + // * /sys/fs/cgroup/cgroup.subtree_control + // * /sys/fs/cgroup/foo/cgroup.subtree_control + // * /sys/fs/cgroup/foo/bar/cgroup.subtree_control + // Note that /sys/fs/cgroup/foo/bar/baz/cgroup.subtree_control does not need to be written. + split := strings.Split(c.path, "/") + var lastErr error + for i, _ := range split { + f := strings.Join(split[:i], "/") + if !strings.HasPrefix(f, c.unifiedMountpoint) || f == c.path { + continue + } + filePath := filepath.Join(f, subtreeControl) + if err := c.writeSubtreeControl(filePath, controllers, t); err != nil { + // When running as rootless, the user may face EPERM on parent groups, but it is neglible when the + // controller is already written. + // So we only return the last error. + lastErr = errors.Wrapf(err, "failed to write subtree controllers %+v to %q", controllers, filePath) + } + } + return lastErr +} + +func (c *Manager) writeSubtreeControl(filePath string, controllers []string, t ControllerToggle) error { + f, err := os.OpenFile(filePath, os.O_WRONLY, 0) if err != nil { return err }