From 24cef0a622bb99fdfafe7898679a95a2a974b499 Mon Sep 17 00:00:00 2001 From: Rahat Mahmood Date: Fri, 18 Mar 2022 01:15:27 -0700 Subject: [PATCH] cgroupfs: Stub control files to allow subcontainer creation with gcontain. PiperOrigin-RevId: 435569386 --- pkg/sentry/fsimpl/cgroupfs/cgroupfs.go | 50 ++++++++++++++++++++++++++ pkg/sentry/fsimpl/cgroupfs/cpu.go | 9 ++--- pkg/sentry/fsimpl/cgroupfs/job.go | 28 +-------------- pkg/sentry/fsimpl/cgroupfs/memory.go | 8 +++-- 4 files changed, 59 insertions(+), 36 deletions(-) diff --git a/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go b/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go index 85b3e8801..de6277e2b 100644 --- a/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go +++ b/pkg/sentry/fsimpl/cgroupfs/cgroupfs.go @@ -57,10 +57,12 @@ package cgroupfs import ( + "bytes" "fmt" "sort" "strconv" "strings" + "sync/atomic" "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/context" @@ -71,6 +73,7 @@ import ( "gvisor.dev/gvisor/pkg/sentry/kernel/auth" "gvisor.dev/gvisor/pkg/sentry/vfs" "gvisor.dev/gvisor/pkg/sync" + "gvisor.dev/gvisor/pkg/usermem" ) const ( @@ -546,6 +549,11 @@ type controllerFile struct { kernfs.DynamicBytesFile } +// SetStat implements kernfs.Inode.SetStat. +func (f *controllerFile) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error { + return f.InodeAttrs.SetStat(ctx, fs, creds, opts) +} + func (fs *filesystem) newControllerFile(ctx context.Context, creds *auth.Credentials, data vfs.DynamicBytesSource) kernfs.Inode { f := &controllerFile{} f.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), data, readonlyFileMode) @@ -568,6 +576,11 @@ type staticControllerFile struct { vfs.StaticData } +// SetStat implements kernfs.Inode.SetStat. +func (f *staticControllerFile) SetStat(ctx context.Context, fs *vfs.Filesystem, creds *auth.Credentials, opts vfs.SetStatOptions) error { + return f.InodeAttrs.SetStat(ctx, fs, creds, opts) +} + // Note: We let the caller provide the mode so that static files may be used to // fake both readable and writable control files. However, static files are // effectively readonly, as attempting to write to them will return EIO @@ -577,3 +590,40 @@ func (fs *filesystem) newStaticControllerFile(ctx context.Context, creds *auth.C f.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), f, mode) return f } + +// stubControllerFile is a writable control file that remembers the control +// value written to it. +// +// +stateify savable +type stubControllerFile struct { + controllerFile + + // data is accessed through atomic ops. + data *int64 +} + +// Generate implements vfs.DynamicBytesSource.Generate. +func (f *stubControllerFile) Generate(ctx context.Context, buf *bytes.Buffer) error { + fmt.Fprintf(buf, "%d\n", atomic.LoadInt64(f.data)) + return nil +} + +// Write implements vfs.WritableDynamicBytesSource.Write. +func (f *stubControllerFile) Write(ctx context.Context, _ *vfs.FileDescription, src usermem.IOSequence, offset int64) (int64, error) { + val, n, err := parseInt64FromString(ctx, src) + if err != nil { + return 0, err + } + atomic.StoreInt64(f.data, val) + return n, nil +} + +// newStubControllerFile creates a new stub controller file tbat loads and +// stores a control value from data. +func (fs *filesystem) newStubControllerFile(ctx context.Context, creds *auth.Credentials, data *int64) kernfs.Inode { + f := &stubControllerFile{ + data: data, + } + f.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), f, writableFileMode) + return f +} diff --git a/pkg/sentry/fsimpl/cgroupfs/cpu.go b/pkg/sentry/fsimpl/cgroupfs/cpu.go index 8fd9b5dec..9c7f25ddd 100644 --- a/pkg/sentry/fsimpl/cgroupfs/cpu.go +++ b/pkg/sentry/fsimpl/cgroupfs/cpu.go @@ -15,9 +15,6 @@ package cgroupfs import ( - "fmt" - - "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs" "gvisor.dev/gvisor/pkg/sentry/kernel/auth" @@ -76,7 +73,7 @@ func (c *cpuController) Clone() controller { // AddControlFiles implements controller.AddControlFiles. func (c *cpuController) AddControlFiles(ctx context.Context, creds *auth.Credentials, _ *cgroupInode, contents map[string]kernfs.Inode) { - contents["cpu.cfs_period_us"] = c.fs.newStaticControllerFile(ctx, creds, linux.FileMode(0644), fmt.Sprintf("%d\n", c.cfsPeriod)) - contents["cpu.cfs_quota_us"] = c.fs.newStaticControllerFile(ctx, creds, linux.FileMode(0644), fmt.Sprintf("%d\n", c.cfsQuota)) - contents["cpu.shares"] = c.fs.newStaticControllerFile(ctx, creds, linux.FileMode(0644), fmt.Sprintf("%d\n", c.shares)) + contents["cpu.cfs_period_us"] = c.fs.newStubControllerFile(ctx, creds, &c.cfsPeriod) + contents["cpu.cfs_quota_us"] = c.fs.newStubControllerFile(ctx, creds, &c.cfsQuota) + contents["cpu.shares"] = c.fs.newStubControllerFile(ctx, creds, &c.shares) } diff --git a/pkg/sentry/fsimpl/cgroupfs/job.go b/pkg/sentry/fsimpl/cgroupfs/job.go index fa0cb7242..31e25a15f 100644 --- a/pkg/sentry/fsimpl/cgroupfs/job.go +++ b/pkg/sentry/fsimpl/cgroupfs/job.go @@ -15,14 +15,9 @@ package cgroupfs import ( - "bytes" - "fmt" - "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs" "gvisor.dev/gvisor/pkg/sentry/kernel/auth" - "gvisor.dev/gvisor/pkg/sentry/vfs" - "gvisor.dev/gvisor/pkg/usermem" ) // +stateify savable @@ -51,26 +46,5 @@ func (c *jobController) Clone() controller { } func (c *jobController) AddControlFiles(ctx context.Context, creds *auth.Credentials, _ *cgroupInode, contents map[string]kernfs.Inode) { - contents["job.id"] = c.fs.newControllerWritableFile(ctx, creds, &jobIDData{c: c}) -} - -// +stateify savable -type jobIDData struct { - c *jobController -} - -// Generate implements vfs.DynamicBytesSource.Generate. -func (d *jobIDData) Generate(ctx context.Context, buf *bytes.Buffer) error { - fmt.Fprintf(buf, "%d\n", d.c.id) - return nil -} - -// Write implements vfs.WritableDynamicBytesSource.Write. -func (d *jobIDData) Write(ctx context.Context, _ *vfs.FileDescription, src usermem.IOSequence, offset int64) (int64, error) { - val, n, err := parseInt64FromString(ctx, src) - if err != nil { - return n, err - } - d.c.id = val - return n, nil + contents["job.id"] = c.fs.newStubControllerFile(ctx, creds, &c.id) } diff --git a/pkg/sentry/fsimpl/cgroupfs/memory.go b/pkg/sentry/fsimpl/cgroupfs/memory.go index 0395cad48..c484ba626 100644 --- a/pkg/sentry/fsimpl/cgroupfs/memory.go +++ b/pkg/sentry/fsimpl/cgroupfs/memory.go @@ -35,6 +35,7 @@ type memoryController struct { limitBytes int64 softLimitBytes int64 moveChargeAtImmigrate int64 + pressureLevel int64 } var _ controller = (*memoryController)(nil) @@ -78,9 +79,10 @@ func (c *memoryController) Clone() controller { // AddControlFiles implements controller.AddControlFiles. func (c *memoryController) AddControlFiles(ctx context.Context, creds *auth.Credentials, _ *cgroupInode, contents map[string]kernfs.Inode) { contents["memory.usage_in_bytes"] = c.fs.newControllerFile(ctx, creds, &memoryUsageInBytesData{}) - contents["memory.limit_in_bytes"] = c.fs.newStaticControllerFile(ctx, creds, linux.FileMode(0644), fmt.Sprintf("%d\n", c.limitBytes)) - contents["memory.soft_limit_in_bytes"] = c.fs.newStaticControllerFile(ctx, creds, linux.FileMode(0644), fmt.Sprintf("%d\n", c.softLimitBytes)) - contents["memory.move_charge_at_immigrate"] = c.fs.newStaticControllerFile(ctx, creds, linux.FileMode(0644), fmt.Sprintf("%d\n", c.moveChargeAtImmigrate)) + contents["memory.limit_in_bytes"] = c.fs.newStubControllerFile(ctx, creds, &c.limitBytes) + contents["memory.soft_limit_in_bytes"] = c.fs.newStubControllerFile(ctx, creds, &c.softLimitBytes) + contents["memory.move_charge_at_immigrate"] = c.fs.newStubControllerFile(ctx, creds, &c.moveChargeAtImmigrate) + contents["memory.pressure_level"] = c.fs.newStaticControllerFile(ctx, creds, linux.FileMode(0644), fmt.Sprintf("%d\n", c.pressureLevel)) } // +stateify savable