Create containers when cgroups already mounted
Runc needs to copy certain files from the top of the cgroup cpuset hierarchy into the container's cpuset cgroup directory. Currently, runc determines which directory is the top of the hierarchy by using the parent dir of the first entry in /proc/self/mountinfo of type cgroup. This creates problems when cgroup subsystems are mounted arbitrarily in different dirs on the host. Now, we use the most deeply nested mountpoint that contains the container's cpuset cgroup directory. Signed-off-by: Konstantinos Karampogias <konstantinos.karampogias@swisscom.com> Signed-off-by: Will Martin <wmartin@pivotal.io>
This commit is contained in:
parent
31980a53ae
commit
f5c5aac958
|
@ -57,10 +57,11 @@ func (s *CpusetGroup) ApplyDir(dir string, cgroup *configs.Cgroup, pid int) erro
|
|||
if dir == "" {
|
||||
return nil
|
||||
}
|
||||
root, err := getCgroupRoot()
|
||||
mountInfo, err := ioutil.ReadFile("/proc/self/mountinfo")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
root := filepath.Dir(cgroups.GetClosestMountpointAncestor(dir, string(mountInfo)))
|
||||
// 'ensureParent' start with parent because we don't want to
|
||||
// explicitly inherit from parent, it could conflict with
|
||||
// 'cpuset.cpu_exclusive'.
|
||||
|
|
|
@ -66,6 +66,21 @@ func isSubsystemAvailable(subsystem string) bool {
|
|||
return avail
|
||||
}
|
||||
|
||||
func GetClosestMountpointAncestor(dir, mountinfo string) string {
|
||||
deepestMountPoint := ""
|
||||
for _, mountInfoEntry := range strings.Split(mountinfo, "\n") {
|
||||
mountInfoParts := strings.Fields(mountInfoEntry)
|
||||
if len(mountInfoParts) < 5 {
|
||||
continue
|
||||
}
|
||||
mountPoint := mountInfoParts[4]
|
||||
if strings.HasPrefix(mountPoint, deepestMountPoint) && strings.HasPrefix(dir, mountPoint) {
|
||||
deepestMountPoint = mountPoint
|
||||
}
|
||||
}
|
||||
return deepestMountPoint
|
||||
}
|
||||
|
||||
func FindCgroupMountpointDir() (string, error) {
|
||||
f, err := os.Open("/proc/self/mountinfo")
|
||||
if err != nil {
|
||||
|
|
|
@ -300,3 +300,34 @@ func TestIgnoreCgroup2Mount(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fakeMountInfo = ` 18 24 0:17 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw
|
||||
100 99 1:31 / /foo/bar rw,relatime - fake fake rw,fake
|
||||
100 99 1:31 / /foo/bar/baz2 rw,relatime - fake fake rw,fake
|
||||
100 99 1:31 / /foo/bar/baz rw,relatime - fake fake rw,fake
|
||||
100 99 1:31 / /foo/bar/bazza rw,relatime - fake fake rw,fake
|
||||
100 99 1:31 / /foo/bar/baz3 rw,relatime - fake fake rw,fake
|
||||
100 99 1:31 / /foo rw,relatime - fake fake rw,fake
|
||||
100 99 1:31 / /unrelated rw,relatime - fake fake rw,fake
|
||||
100 99 1:31 / / rw,relatime - fake fake rw,fake
|
||||
`
|
||||
|
||||
func TestGetClosestMountpointAncestor(t *testing.T) {
|
||||
testCases := []struct {
|
||||
input string
|
||||
mountinfos string
|
||||
output string
|
||||
}{
|
||||
{input: "/foo/bar/baz/a/b/c", mountinfos: fakeMountInfo, output: "/foo/bar/baz"},
|
||||
{input: "/foo/bar/baz", mountinfos: fakeMountInfo, output: "/foo/bar/baz"},
|
||||
{input: "/foo/bar/bazza", mountinfos: fakeMountInfo, output: "/foo/bar/bazza"},
|
||||
{input: "/a/b/c/d", mountinfos: fakeMountInfo, output: "/"},
|
||||
}
|
||||
|
||||
for _, c := range testCases {
|
||||
mountpoint := GetClosestMountpointAncestor(c.input, c.mountinfos)
|
||||
if mountpoint != c.output {
|
||||
t.Errorf("expected %s, got %s", c.output, mountpoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue