Add /proc/[pid]/cgroups file

Updates #1195

PiperOrigin-RevId: 290298266
This commit is contained in:
Fabricio Voznika
2020-01-17 10:41:44 -08:00
committed by gVisor bot
parent ff99609858
commit 8e8d0f96f6
5 changed files with 65 additions and 17 deletions
+12 -1
View File
@@ -47,7 +47,12 @@ func (ft *procFSType) GetFilesystem(ctx context.Context, vfsObj *vfs.VirtualFile
procfs := &kernfs.Filesystem{}
procfs.VFSFilesystem().Init(vfsObj, procfs)
_, dentry := newTasksInode(procfs, k, pidns)
var data *InternalData
if opts.InternalData != nil {
data = opts.InternalData.(*InternalData)
}
_, dentry := newTasksInode(procfs, k, pidns, data.Cgroups)
return procfs.VFSFilesystem(), dentry.VFSDentry(), nil
}
@@ -78,3 +83,9 @@ var _ dynamicInode = (*staticFile)(nil)
func newStaticFile(data string) *staticFile {
return &staticFile{StaticData: vfs.StaticData{Data: data}}
}
// InternalData contains internal data passed in to the procfs mount via
// vfs.GetFilesystemOptions.InternalData.
type InternalData struct {
Cgroups map[string]string
}
+10 -8
View File
@@ -35,18 +35,20 @@ type subtasksInode struct {
kernfs.InodeAttrs
kernfs.OrderedChildren
task *kernel.Task
pidns *kernel.PIDNamespace
inoGen InoGenerator
task *kernel.Task
pidns *kernel.PIDNamespace
inoGen InoGenerator
cgroupControllers map[string]string
}
var _ kernfs.Inode = (*subtasksInode)(nil)
func newSubtasks(task *kernel.Task, pidns *kernel.PIDNamespace, inoGen InoGenerator) *kernfs.Dentry {
func newSubtasks(task *kernel.Task, pidns *kernel.PIDNamespace, inoGen InoGenerator, cgroupControllers map[string]string) *kernfs.Dentry {
subInode := &subtasksInode{
task: task,
pidns: pidns,
inoGen: inoGen,
task: task,
pidns: pidns,
inoGen: inoGen,
cgroupControllers: cgroupControllers,
}
// Note: credentials are overridden by taskOwnedInode.
subInode.InodeAttrs.Init(task.Credentials(), inoGen.NextIno(), linux.ModeDirectory|0555)
@@ -79,7 +81,7 @@ func (i *subtasksInode) Lookup(ctx context.Context, name string) (*vfs.Dentry, e
return nil, syserror.ENOENT
}
subTaskDentry := newTaskInode(i.inoGen, subTask, i.pidns, false)
subTaskDentry := newTaskInode(i.inoGen, subTask, i.pidns, false, i.cgroupControllers)
return subTaskDentry.VFSDentry(), nil
}
+25 -5
View File
@@ -15,6 +15,7 @@
package proc
import (
"bytes"
"fmt"
"gvisor.dev/gvisor/pkg/abi/linux"
@@ -42,7 +43,7 @@ type taskInode struct {
var _ kernfs.Inode = (*taskInode)(nil)
func newTaskInode(inoGen InoGenerator, task *kernel.Task, pidns *kernel.PIDNamespace, isThreadGroup bool) *kernfs.Dentry {
func newTaskInode(inoGen InoGenerator, task *kernel.Task, pidns *kernel.PIDNamespace, isThreadGroup bool, cgroupControllers map[string]string) *kernfs.Dentry {
contents := map[string]*kernfs.Dentry{
"auxv": newTaskOwnedFile(task, inoGen.NextIno(), 0444, &auxvData{task: task}),
"cmdline": newTaskOwnedFile(task, inoGen.NextIno(), 0444, &cmdlineData{task: task, arg: cmdlineDataArg}),
@@ -68,11 +69,11 @@ func newTaskInode(inoGen InoGenerator, task *kernel.Task, pidns *kernel.PIDNames
"uid_map": newTaskOwnedFile(task, inoGen.NextIno(), 0644, &idMapData{task: task, gids: false}),
}
if isThreadGroup {
contents["task"] = newSubtasks(task, pidns, inoGen)
contents["task"] = newSubtasks(task, pidns, inoGen, cgroupControllers)
}
if len(cgroupControllers) > 0 {
contents["cgroup"] = newTaskOwnedFile(task, inoGen.NextIno(), 0444, newCgroupData(cgroupControllers))
}
//if len(p.cgroupControllers) > 0 {
// contents["cgroup"] = newCGroupInode(t, msrc, p.cgroupControllers)
//}
taskInode := &taskInode{task: task}
// Note: credentials are overridden by taskOwnedInode.
@@ -227,3 +228,22 @@ func newNamespaceSymlink(task *kernel.Task, ino uint64, ns string) *kernfs.Dentr
d.Init(taskInode)
return d
}
// newCgroupData creates inode that shows cgroup information.
// From man 7 cgroups: "For each cgroup hierarchy of which the process is a
// member, there is one entry containing three colon-separated fields:
// hierarchy-ID:controller-list:cgroup-path"
func newCgroupData(controllers map[string]string) dynamicInode {
buf := bytes.Buffer{}
// The hierarchy ids must be positive integers (for cgroup v1), but the
// exact number does not matter, so long as they are unique. We can
// just use a counter, but since linux sorts this file in descending
// order, we must count down to preserve this behavior.
i := len(controllers)
for name, dir := range controllers {
fmt.Fprintf(&buf, "%d:%s:%s\n", i, name, dir)
i--
}
return newStaticFile(buf.String())
}
+8 -2
View File
@@ -54,11 +54,16 @@ type tasksInode struct {
// Linux. So handle them outside of OrderedChildren.
selfSymlink *vfs.Dentry
threadSelfSymlink *vfs.Dentry
// cgroupControllers is a map of controller name to directory in the
// cgroup hierarchy. These controllers are immutable and will be listed
// in /proc/pid/cgroup if not nil.
cgroupControllers map[string]string
}
var _ kernfs.Inode = (*tasksInode)(nil)
func newTasksInode(inoGen InoGenerator, k *kernel.Kernel, pidns *kernel.PIDNamespace) (*tasksInode, *kernfs.Dentry) {
func newTasksInode(inoGen InoGenerator, k *kernel.Kernel, pidns *kernel.PIDNamespace, cgroupControllers map[string]string) (*tasksInode, *kernfs.Dentry) {
root := auth.NewRootCredentials(pidns.UserNamespace())
contents := map[string]*kernfs.Dentry{
"cpuinfo": newDentry(root, inoGen.NextIno(), 0444, newStaticFile(cpuInfoData(k))),
@@ -78,6 +83,7 @@ func newTasksInode(inoGen InoGenerator, k *kernel.Kernel, pidns *kernel.PIDNames
inoGen: inoGen,
selfSymlink: newSelfSymlink(root, inoGen.NextIno(), 0444, pidns).VFSDentry(),
threadSelfSymlink: newThreadSelfSymlink(root, inoGen.NextIno(), 0444, pidns).VFSDentry(),
cgroupControllers: cgroupControllers,
}
inode.InodeAttrs.Init(root, inoGen.NextIno(), linux.ModeDirectory|0555)
@@ -111,7 +117,7 @@ func (i *tasksInode) Lookup(ctx context.Context, name string) (*vfs.Dentry, erro
return nil, syserror.ENOENT
}
taskDentry := newTaskInode(i.inoGen, task, i.pidns, true)
taskDentry := newTaskInode(i.inoGen, task, i.pidns, true, i.cgroupControllers)
return taskDentry.VFSDentry(), nil
}
+10 -1
View File
@@ -87,6 +87,7 @@ func checkTasksStaticFiles(gots []vfs.Dirent) ([]vfs.Dirent, error) {
func checkTaskStaticFiles(gots []vfs.Dirent) ([]vfs.Dirent, error) {
wants := map[string]vfs.Dirent{
"auxv": {Type: linux.DT_REG},
"cgroup": {Type: linux.DT_REG},
"cmdline": {Type: linux.DT_REG},
"comm": {Type: linux.DT_REG},
"environ": {Type: linux.DT_REG},
@@ -145,7 +146,15 @@ func setup() (context.Context, *vfs.VirtualFilesystem, vfs.VirtualDentry, error)
vfsObj.MustRegisterFilesystemType("procfs", &procFSType{}, &vfs.RegisterFilesystemTypeOptions{
AllowUserMount: true,
})
mntns, err := vfsObj.NewMountNamespace(ctx, creds, "", "procfs", &vfs.GetFilesystemOptions{})
fsOpts := vfs.GetFilesystemOptions{
InternalData: &InternalData{
Cgroups: map[string]string{
"cpuset": "/foo/cpuset",
"memory": "/foo/memory",
},
},
}
mntns, err := vfsObj.NewMountNamespace(ctx, creds, "", "procfs", &fsOpts)
if err != nil {
return nil, nil, vfs.VirtualDentry{}, fmt.Errorf("NewMountNamespace(): %v", err)
}