diff --git a/pkg/sentry/fsimpl/cgroupfs/base.go b/pkg/sentry/fsimpl/cgroupfs/base.go index 30b4c5bfc..b5507958d 100644 --- a/pkg/sentry/fsimpl/cgroupfs/base.go +++ b/pkg/sentry/fsimpl/cgroupfs/base.go @@ -25,6 +25,7 @@ import ( "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/hostarch" + "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs" "gvisor.dev/gvisor/pkg/sentry/kernel" "gvisor.dev/gvisor/pkg/sentry/kernel/auth" @@ -151,6 +152,9 @@ type controller interface { type cgroupInode struct { dir + // id is the id of this cgroup. + id uint32 + // controllers is the set of controllers for this cgroup. This is used to // store controller-specific state per cgroup. The set of controllers should // match the controllers for this hierarchy as tracked by the filesystem @@ -175,6 +179,16 @@ func (fs *filesystem) newCgroupInode(ctx context.Context, creds *auth.Credential } c.dir.cgi = c + k := kernel.KernelFromContext(ctx) + r := k.CgroupRegistry() + // Assign id for the cgroup. + cid, err := r.NextCgroupID() + if err != nil { + log.Warningf("cgroupfs newCgroupInode: Failed to assign id to the cgroup: %v", err) + } + c.id = cid + r.AddCgroup(c) + contents := make(map[string]kernfs.Inode) contents["cgroup.procs"] = fs.newControllerWritableFile(ctx, creds, &cgroupProcsData{c}, false) contents["tasks"] = fs.newControllerWritableFile(ctx, creds, &tasksData{c}, false) @@ -382,6 +396,11 @@ func (c *cgroupInode) WriteControl(ctx context.Context, name string, value strin return nil } +// ID implements kernel.CgroupImpl.ID. +func (c *cgroupInode) ID() uint32 { + return c.id +} + func sortTIDs(tids []kernel.ThreadID) { sort.Slice(tids, func(i, j int) bool { return tids[i] < tids[j] }) } diff --git a/pkg/sentry/kernel/cgroup.go b/pkg/sentry/kernel/cgroup.go index aefe0dae5..b7ab1963d 100644 --- a/pkg/sentry/kernel/cgroup.go +++ b/pkg/sentry/kernel/cgroup.go @@ -31,6 +31,9 @@ import ( // InvalidCgroupHierarchyID indicates an uninitialized hierarchy ID. const InvalidCgroupHierarchyID uint32 = 0 +// InvalidCgroupID indicates an uninitialized cgroup ID. +const InvalidCgroupID uint32 = 0 + // CgroupControllerType is the name of a cgroup controller. type CgroupControllerType string @@ -212,6 +215,9 @@ type CgroupImpl interface { // WriteControl allows a background context to write a cgroup's control // values. WriteControl(ctx context.Context, name string, val string) error + + // ID returns the id of this cgroup. + ID() uint32 } // hierarchy represents a cgroupfs filesystem instance, with a unique set of @@ -268,6 +274,11 @@ type CgroupRegistry struct { // lastHierarchyID atomicbitops.Uint32 + // lastCgroupID is the id of the last allocated cgroup. Valid ids are + // from 1 to math.MaxUint32. + // + lastCgroupID atomicbitops.Uint32 + mu cgroupMutex `state:"nosave"` // controllers is the set of currently known cgroup controllers on the @@ -287,6 +298,12 @@ type CgroupRegistry struct { // // +checklocks:mu hierarchiesByName map[string]hierarchy + + // cgroups is the active set of cgroups. This contains all the cgroups + // on the system. + // + // +checklocks:mu + cgroups map[uint32]CgroupImpl } func newCgroupRegistry() *CgroupRegistry { @@ -294,6 +311,7 @@ func newCgroupRegistry() *CgroupRegistry { controllers: make(map[CgroupControllerType]CgroupController), hierarchies: make(map[uint32]hierarchy), hierarchiesByName: make(map[string]hierarchy), + cgroups: make(map[uint32]CgroupImpl), } } @@ -512,3 +530,29 @@ func (r *CgroupRegistry) GenerateProcCgroups(buf *bytes.Buffer) { fmt.Fprint(buf, e) } } + +// NextCgroupID returns a newly allocated, unique cgroup ID. +func (r *CgroupRegistry) NextCgroupID() (uint32, error) { + if cid := r.lastCgroupID.Add(1); cid != 0 { + return cid, nil + } + return InvalidCgroupID, fmt.Errorf("cgroup ID overflow") +} + +// AddCgroup adds the ID and cgroup in the map. +func (r *CgroupRegistry) AddCgroup(cg CgroupImpl) { + r.mu.Lock() + r.cgroups[cg.ID()] = cg + r.mu.Unlock() +} + +// GetCgroup returns the cgroup associated with the cgroup ID. +func (r *CgroupRegistry) GetCgroup(cid uint32) (CgroupImpl, error) { + r.mu.Lock() + defer r.mu.Unlock() + cg, ok := r.cgroups[cid] + if !ok { + return nil, fmt.Errorf("cgroup with ID %d does not exist", cid) + } + return cg, nil +}