summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fsimpl/cgroupfs/cpuset.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/sentry/fsimpl/cgroupfs/cpuset.go')
-rw-r--r--pkg/sentry/fsimpl/cgroupfs/cpuset.go114
1 files changed, 111 insertions, 3 deletions
diff --git a/pkg/sentry/fsimpl/cgroupfs/cpuset.go b/pkg/sentry/fsimpl/cgroupfs/cpuset.go
index ac547f8e2..62e7029da 100644
--- a/pkg/sentry/fsimpl/cgroupfs/cpuset.go
+++ b/pkg/sentry/fsimpl/cgroupfs/cpuset.go
@@ -15,25 +15,133 @@
package cgroupfs
import (
+ "bytes"
+ "fmt"
+
+ "gvisor.dev/gvisor/pkg/bitmap"
"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"
+ "gvisor.dev/gvisor/pkg/usermem"
)
// +stateify savable
type cpusetController struct {
controllerCommon
+
+ maxCpus uint32
+ maxMems uint32
+
+ cpus *bitmap.Bitmap
+ mems *bitmap.Bitmap
}
var _ controller = (*cpusetController)(nil)
-func newCPUSetController(fs *filesystem) *cpusetController {
- c := &cpusetController{}
+func newCPUSetController(k *kernel.Kernel, fs *filesystem) *cpusetController {
+ cores := uint32(k.ApplicationCores())
+ cpus := bitmap.New(cores)
+ cpus.FlipRange(0, cores)
+ mems := bitmap.New(1)
+ mems.FlipRange(0, 1)
+ c := &cpusetController{
+ cpus: &cpus,
+ mems: &mems,
+ maxCpus: uint32(k.ApplicationCores()),
+ maxMems: 1, // We always report a single NUMA node.
+ }
c.controllerCommon.init(controllerCPUSet, fs)
return c
}
// AddControlFiles implements controller.AddControlFiles.
func (c *cpusetController) AddControlFiles(ctx context.Context, creds *auth.Credentials, _ *cgroupInode, contents map[string]kernfs.Inode) {
- // This controller is currently intentionally empty.
+ contents["cpuset.cpus"] = c.fs.newControllerWritableFile(ctx, creds, &cpusData{c: c})
+ contents["cpuset.mems"] = c.fs.newControllerWritableFile(ctx, creds, &memsData{c: c})
+}
+
+// +stateify savable
+type cpusData struct {
+ c *cpusetController
+}
+
+// Generate implements vfs.DynamicBytesSource.Generate.
+func (d *cpusData) Generate(ctx context.Context, buf *bytes.Buffer) error {
+ fmt.Fprintf(buf, "%s\n", formatBitmap(d.c.cpus))
+ return nil
+}
+
+// Write implements vfs.WritableDynamicBytesSource.Write.
+func (d *cpusData) Write(ctx context.Context, src usermem.IOSequence, offset int64) (int64, error) {
+ src = src.DropFirst64(offset)
+ if src.NumBytes() > hostarch.PageSize {
+ return 0, linuxerr.EINVAL
+ }
+
+ t := kernel.TaskFromContext(ctx)
+ buf := t.CopyScratchBuffer(hostarch.PageSize)
+ n, err := src.CopyIn(ctx, buf)
+ if err != nil {
+ return 0, err
+ }
+ buf = buf[:n]
+
+ b, err := parseBitmap(string(buf), d.c.maxCpus)
+ if err != nil {
+ log.Warningf("cgroupfs cpuset controller: Failed to parse bitmap: %v", err)
+ return 0, linuxerr.EINVAL
+ }
+
+ if got, want := b.Maximum(), d.c.maxCpus; got > want {
+ log.Warningf("cgroupfs cpuset controller: Attempted to specify cpuset.cpus beyond highest available cpu: got %d, want %d", got, want)
+ return 0, linuxerr.EINVAL
+ }
+
+ d.c.cpus = b
+ return int64(n), nil
+}
+
+// +stateify savable
+type memsData struct {
+ c *cpusetController
+}
+
+// Generate implements vfs.DynamicBytesSource.Generate.
+func (d *memsData) Generate(ctx context.Context, buf *bytes.Buffer) error {
+ fmt.Fprintf(buf, "%s\n", formatBitmap(d.c.mems))
+ return nil
+}
+
+// Write implements vfs.WritableDynamicBytesSource.Write.
+func (d *memsData) Write(ctx context.Context, src usermem.IOSequence, offset int64) (int64, error) {
+ src = src.DropFirst64(offset)
+ if src.NumBytes() > hostarch.PageSize {
+ return 0, linuxerr.EINVAL
+ }
+
+ t := kernel.TaskFromContext(ctx)
+ buf := t.CopyScratchBuffer(hostarch.PageSize)
+ n, err := src.CopyIn(ctx, buf)
+ if err != nil {
+ return 0, err
+ }
+ buf = buf[:n]
+
+ b, err := parseBitmap(string(buf), d.c.maxMems)
+ if err != nil {
+ log.Warningf("cgroupfs cpuset controller: Failed to parse bitmap: %v", err)
+ return 0, linuxerr.EINVAL
+ }
+
+ if got, want := b.Maximum(), d.c.maxMems; got > want {
+ log.Warningf("cgroupfs cpuset controller: Attempted to specify cpuset.mems beyond highest available node: got %d, want %d", got, want)
+ return 0, linuxerr.EINVAL
+ }
+
+ d.c.mems = b
+ return int64(n), nil
}