diff --git a/cli/create.go b/cli/create.go index d7e5abec8b..f6a9f406b1 100644 --- a/cli/create.go +++ b/cli/create.go @@ -287,8 +287,13 @@ func createCgroupsFiles(containerID string, cgroupsDirPath string, cgroupsPathLi } if strings.Contains(cgroupsPath, "cpu") && cgroupsDirPath != "" { - parent := strings.TrimSuffix(cgroupsPath, cgroupsDirPath) - copyParentCPUSet(cgroupsPath, parent) + root, err := getCgroupsRootPath(procMountInfo) + if err != nil { + return err + } + if err := repeatCopy(cgroupsPath, root); err != nil { + return fmt.Errorf("Fail to copy cpuset from parent: %s", err) + } } tasksFilePath := filepath.Join(cgroupsPath, cgroupsTasksFile) @@ -348,6 +353,34 @@ func createPIDFile(pidFilePath string, pid int) error { return nil } +// repeatCopy copies data from parent directory until +// cpuset cgroup root to avoid parent has zero data. +func repeatCopy(path, root string) error { + if !fileExists(filepath.Join(path, "cpuset.cpus")) || !fileExists(filepath.Join(path, "cpuset.mems")) { + return nil + } + + parent := filepath.Dir(path) + if filepath.Clean(parent) == root { + return nil + } + + // cgroup path get error, stop the loop + if parent == path { + return fmt.Errorf("cpu cgroup gets wrong path %s", path) + } + + if err := repeatCopy(parent, root); err != nil { + return err + } + + if err := os.MkdirAll(path, cgroupsDirMode); err != nil { + return err + } + + return copyParentCPUSet(path, parent) +} + // copyParentCPUSet copies the cpuset.cpus and cpuset.mems from the parent // directory to the current directory if the file's contents are 0 func copyParentCPUSet(current, parent string) error { diff --git a/cli/create_test.go b/cli/create_test.go index 9143735467..6dd73a2b43 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -631,14 +631,14 @@ func TestCreateCreateCgroupsFilesFail(t *testing.T) { } // Override - cgroupsDirPath = filepath.Join(tmpdir, "cgroups") - err = os.MkdirAll(cgroupsDirPath, testDirMode) + cgroupsRootPath = filepath.Join(tmpdir, "cgroups") + err = os.MkdirAll(cgroupsRootPath, testDirMode) assert.NoError(err) // Set a relative path spec.Linux.CgroupsPath = "./a/relative/path" - dir := filepath.Join(cgroupsDirPath, "memory") + dir := filepath.Join(cgroupsRootPath, "memory") // Stop directory from being created err = os.MkdirAll(dir, os.FileMode(0000)) diff --git a/cli/oci.go b/cli/oci.go index 059e212d4a..ef9469b3f1 100644 --- a/cli/oci.go +++ b/cli/oci.go @@ -38,7 +38,7 @@ const ( var errNeedLinuxResource = errors.New("Linux resource cannot be empty") -var cgroupsDirPath string +var cgroupsRootPath string var procMountInfo = "/proc/self/mountinfo" @@ -189,14 +189,14 @@ func processCgroupsPathForResource(ociSpec oci.CompatOCISpec, resource string, i } var err error - cgroupsDirPath, err = getCgroupsDirPath(procMountInfo) + cgroupsRootPath, err = getCgroupsRootPath(procMountInfo) if err != nil { - return "", fmt.Errorf("get CgroupsDirPath error: %s", err) + return "", fmt.Errorf("get CgroupsRootPath error: %s", err) } // Relative cgroups path provided. if filepath.IsAbs(ociSpec.Linux.CgroupsPath) == false { - return filepath.Join(cgroupsDirPath, resource, ociSpec.Linux.CgroupsPath), nil + return filepath.Join(cgroupsRootPath, resource, ociSpec.Linux.CgroupsPath), nil } // Absolute cgroups path provided. @@ -214,7 +214,7 @@ func processCgroupsPathForResource(ociSpec oci.CompatOCISpec, resource string, i // According to the OCI spec, an absolute path should be // interpreted as relative to the system cgroup mount point // when there is no cgroup mount point. - return filepath.Join(cgroupsDirPath, resource, ociSpec.Linux.CgroupsPath), nil + return filepath.Join(cgroupsRootPath, resource, ociSpec.Linux.CgroupsPath), nil } if cgroupMount.Destination == "" { @@ -306,9 +306,9 @@ func noNeedForOutput(detach bool, tty bool) bool { return true } -func getCgroupsDirPath(mountInfoFile string) (string, error) { - if cgroupsDirPath != "" { - return cgroupsDirPath, nil +func getCgroupsRootPath(mountInfoFile string) (string, error) { + if cgroupsRootPath != "" { + return cgroupsRootPath, nil } f, err := os.Open(mountInfoFile) diff --git a/cli/oci_test.go b/cli/oci_test.go index f856df8946..cbb5a60e83 100644 --- a/cli/oci_test.go +++ b/cli/oci_test.go @@ -213,7 +213,7 @@ func TestProcessCgroupsPathEmptyResources(t *testing.T) { func TestProcessCgroupsPathRelativePathSuccessful(t *testing.T) { relativeCgroupsPath := "relative/cgroups/path" - cgroupsDirPath = "/foo/runtime/base" + cgroupsRootPath = "/foo/runtime/base" ociSpec := oci.CompatOCISpec{} @@ -224,7 +224,7 @@ func TestProcessCgroupsPathRelativePathSuccessful(t *testing.T) { for _, d := range cgroupTestData { ociSpec.Linux.Resources = d.linuxSpec - p := filepath.Join(cgroupsDirPath, d.resource, relativeCgroupsPath) + p := filepath.Join(cgroupsRootPath, d.resource, relativeCgroupsPath) testProcessCgroupsPath(t, ociSpec, []string{p}) } @@ -232,7 +232,7 @@ func TestProcessCgroupsPathRelativePathSuccessful(t *testing.T) { func TestProcessCgroupsPathAbsoluteNoCgroupMountSuccessful(t *testing.T) { absoluteCgroupsPath := "/absolute/cgroups/path" - cgroupsDirPath = "/foo/runtime/base" + cgroupsRootPath = "/foo/runtime/base" ociSpec := oci.CompatOCISpec{} @@ -243,7 +243,7 @@ func TestProcessCgroupsPathAbsoluteNoCgroupMountSuccessful(t *testing.T) { for _, d := range cgroupTestData { ociSpec.Linux.Resources = d.linuxSpec - p := filepath.Join(cgroupsDirPath, d.resource, absoluteCgroupsPath) + p := filepath.Join(cgroupsRootPath, d.resource, absoluteCgroupsPath) testProcessCgroupsPath(t, ociSpec, []string{p}) } @@ -422,12 +422,12 @@ func TestIsCgroupMounted(t *testing.T) { assert.False(isCgroupMounted(os.TempDir()), "%s is not a cgroup", os.TempDir()) - cgroupsDirPath = "" - cgroupRootPath, err := getCgroupsDirPath(procMountInfo) + cgroupsRootPath = "" + path, err := getCgroupsRootPath(procMountInfo) if err != nil { assert.NoError(err) } - memoryCgroupPath := filepath.Join(cgroupRootPath, "memory") + memoryCgroupPath := filepath.Join(path, "memory") if _, err := os.Stat(memoryCgroupPath); os.IsNotExist(err) { t.Skipf("memory cgroup does not exist: %s", memoryCgroupPath) } @@ -494,15 +494,15 @@ func TestGetCgroupsDirPath(t *testing.T) { file := filepath.Join(dir, "mountinfo") //file does not exist, should error here - _, err = getCgroupsDirPath(file) + _, err = getCgroupsRootPath(file) assert.Error(err) for _, d := range data { err := ioutil.WriteFile(file, []byte(d.contents), testFileMode) assert.NoError(err) - cgroupsDirPath = "" - path, err := getCgroupsDirPath(file) + cgroupsRootPath = "" + path, err := getCgroupsRootPath(file) if d.expectError { assert.Error(err, fmt.Sprintf("got %q, test data: %+v", path, d)) } else {