diff --git a/libcontainer/cgroups/cgroups_test.go b/libcontainer/cgroups/cgroups_test.go index 597834a07af..2f702bc2ef0 100644 --- a/libcontainer/cgroups/cgroups_test.go +++ b/libcontainer/cgroups/cgroups_test.go @@ -3,27 +3,16 @@ package cgroups import ( - "bytes" "testing" ) -const ( - cgroupsContents = `11:hugetlb:/ -10:perf_event:/ -9:blkio:/ -8:net_cls:/ -7:freezer:/ -6:devices:/ -5:memory:/ -4:cpuacct,cpu:/ -3:cpuset:/ -2:name=systemd:/user.slice/user-1000.slice/session-16.scope` -) - func TestParseCgroups(t *testing.T) { - r := bytes.NewBuffer([]byte(cgroupsContents)) - _, err := ParseCgroupFile("blkio", r) + cgroups, err := ParseCgroupFile("/proc/self/cgroup") if err != nil { t.Fatal(err) } + + if _, ok := cgroups["cpu"]; !ok { + t.Fail() + } } diff --git a/libcontainer/cgroups/utils.go b/libcontainer/cgroups/utils.go index 72a8c014083..4f84a28a8f8 100644 --- a/libcontainer/cgroups/utils.go +++ b/libcontainer/cgroups/utils.go @@ -5,7 +5,6 @@ package cgroups import ( "bufio" "fmt" - "io" "io/ioutil" "os" "path/filepath" @@ -99,12 +98,12 @@ type Mount struct { Subsystems []string } -func (m Mount) GetThisCgroupDir() (string, error) { +func (m Mount) GetThisCgroupDir(cgroups map[string]string) (string, error) { if len(m.Subsystems) == 0 { return "", fmt.Errorf("no subsystem for mount") } - return GetThisCgroupDir(m.Subsystems[0]) + return getControllerPath(m.Subsystems[0], cgroups) } func GetCgroupMounts() ([]Mount, error) { @@ -170,23 +169,22 @@ func GetAllSubsystems() ([]string, error) { // Returns the relative path to the cgroup docker is running in. func GetThisCgroupDir(subsystem string) (string, error) { - f, err := os.Open("/proc/self/cgroup") + cgroups, err := ParseCgroupFile("/proc/self/cgroup") if err != nil { return "", err } - defer f.Close() - return ParseCgroupFile(subsystem, f) + return getControllerPath(subsystem, cgroups) } func GetInitCgroupDir(subsystem string) (string, error) { - f, err := os.Open("/proc/1/cgroup") + + cgroups, err := ParseCgroupFile("/proc/1/cgroup") if err != nil { return "", err } - defer f.Close() - return ParseCgroupFile(subsystem, f) + return getControllerPath(subsystem, cgroups) } func ReadProcsFile(dir string) ([]int, error) { @@ -213,23 +211,40 @@ func ReadProcsFile(dir string) ([]int, error) { return out, nil } -func ParseCgroupFile(subsystem string, r io.Reader) (string, error) { - s := bufio.NewScanner(r) +func ParseCgroupFile(path string) (map[string]string, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + s := bufio.NewScanner(f) + cgroups := make(map[string]string) for s.Scan() { if err := s.Err(); err != nil { - return "", err + return nil, err } text := s.Text() parts := strings.Split(text, ":") for _, subs := range strings.Split(parts[1], ",") { - if subs == subsystem || subs == cgroupNamePrefix+subsystem { - return parts[2], nil - } + cgroups[subs] = parts[2] } } + return cgroups, nil +} + +func getControllerPath(subsystem string, cgroups map[string]string) (string, error) { + + if p, ok := cgroups[subsystem]; ok { + return p, nil + } + + if p, ok := cgroups[cgroupNamePrefix+subsystem]; ok { + return p, nil + } return "", NewNotFoundError(subsystem) } diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go index 9210ec6a3b9..79d41768786 100644 --- a/libcontainer/container_linux.go +++ b/libcontainer/container_linux.go @@ -411,7 +411,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { return err } - err = c.criuSwrk(nil, req, criuOpts) + err = c.criuSwrk(nil, req, criuOpts, false) if err != nil { return err } @@ -504,6 +504,7 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { FileLocks: proto.Bool(criuOpts.FileLocks), }, } + for _, m := range c.config.Mounts { switch m.Device { case "bind": @@ -561,14 +562,36 @@ func (c *linuxContainer) Restore(process *Process, criuOpts *CriuOpts) error { } } - err = c.criuSwrk(process, req, criuOpts) + err = c.criuSwrk(process, req, criuOpts, true) if err != nil { return err } return nil } -func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts) error { +func (c *linuxContainer) criuApplyCgroups(pid int, req *criurpc.CriuReq) error { + if err := c.cgroupManager.Apply(pid); err != nil { + return err + } + + path := fmt.Sprintf("/proc/%d/cgroup", pid) + cgroupsPaths, err := cgroups.ParseCgroupFile(path) + if err != nil { + return err + } + + for c, p := range cgroupsPaths { + cgroupRoot := &criurpc.CgroupRoot{ + Ctrl: proto.String(c), + Path: proto.String(p), + } + req.Opts.CgRoot = append(req.Opts.CgRoot, cgroupRoot) + } + + return nil +} + +func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts *CriuOpts, applyCgroups bool) error { fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET|syscall.SOCK_CLOEXEC, 0) if err != nil { return err @@ -602,6 +625,13 @@ func (c *linuxContainer) criuSwrk(process *Process, req *criurpc.CriuReq, opts * } }() + if applyCgroups { + err := c.criuApplyCgroups(cmd.Process.Pid, req) + if err != nil { + return err + } + } + var extFds []string if process != nil { extFds, err = getPipeFds(cmd.Process.Pid) diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index ecdc7ca64f6..77593fe38ea 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -253,10 +253,15 @@ func getCgroupMounts(m *configs.Mount) ([]*configs.Mount, error) { return nil, err } + cgroupPaths, err := cgroups.ParseCgroupFile("/proc/self/cgroup") + if err != nil { + return nil, err + } + var binds []*configs.Mount for _, mm := range mounts { - dir, err := mm.GetThisCgroupDir() + dir, err := mm.GetThisCgroupDir(cgroupPaths) if err != nil { return nil, err }