diff --git a/BUILD b/BUILD index 6ace559a2..7ba93a3de 100644 --- a/BUILD +++ b/BUILD @@ -133,7 +133,7 @@ go_path( # binaries have been factored into a cli package, which is # a good practice in any case. "//runsc/cli", - "//shim/cli", + "//shim/v1/cli", "//webhook/pkg/cli", "//tools/checklocks", diff --git a/nogo.yaml b/nogo.yaml index 8d4d4eeb5..2bd5acf61 100644 --- a/nogo.yaml +++ b/nogo.yaml @@ -84,8 +84,8 @@ global: - "panic recovered: .*types/sizes.go:82: assertion failed" exclude: # Generated: exempt all. - - pkg/shim/runtimeoptions/runtimeoptions_cri.go - - pkg/shim/runtimeoptions/v14/runtimeoptions_cri.go + - pkg/shim/v1/runtimeoptions/runtimeoptions_cri.go + - pkg/shim/v1/runtimeoptions/v14/runtimeoptions_cri.go analyzers: asmdecl: generated: # Enabled. diff --git a/pkg/sentry/control/state.go b/pkg/sentry/control/state.go index 4eb7ec300..b3b284f0c 100644 --- a/pkg/sentry/control/state.go +++ b/pkg/sentry/control/state.go @@ -18,8 +18,6 @@ import ( "errors" "fmt" - "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sentry/kernel" "gvisor.dev/gvisor/pkg/sentry/pgalloc" "gvisor.dev/gvisor/pkg/sentry/state" @@ -84,18 +82,7 @@ func (s *State) Save(o *SaveOpts, _ *struct{}) error { Key: o.Key, Metadata: o.Metadata, MemoryFileSaveOpts: o.MemoryFileSaveOpts, - Callback: func(err error) { - if err == nil { - log.Infof("Save succeeded: exiting...") - s.Kernel.SetSaveSuccess(false /* autosave */) - } else { - log.Warningf("Save failed: %v", err) - s.Kernel.SetSaveError(err) - } - if !o.Resume { - s.Kernel.Kill(linux.WaitStatusExit(0)) - } - }, + Resume: o.Resume, } if o.HavePagesFile { saveOpts.PagesMetadata, err = o.ReleaseFD(1) diff --git a/pkg/sentry/fsimpl/gofer/save_restore.go b/pkg/sentry/fsimpl/gofer/save_restore.go index 66bde23d1..3d1249f37 100644 --- a/pkg/sentry/fsimpl/gofer/save_restore.go +++ b/pkg/sentry/fsimpl/gofer/save_restore.go @@ -31,6 +31,8 @@ import ( "gvisor.dev/gvisor/pkg/sentry/vfs" ) +var _ vfs.FilesystemImplSaveRestoreExtension = (*filesystem)(nil) + // +stateify savable type savedDentryRW struct { read bool @@ -134,6 +136,11 @@ func (d *dentry) beforeSave() { } } +// BeforeResume implements vfs.FilesystemImplSaveRestoreExtension.BeforeResume. +func (fs *filesystem) BeforeResume(ctx context.Context) { + fs.savedDentryRW = nil +} + // afterLoad is invoked by stateify. func (fs *filesystem) afterLoad(ctx goContext.Context) { fs.mf = pgalloc.MemoryFileFromContext(ctx) diff --git a/pkg/sentry/fsimpl/proc/tasks.go b/pkg/sentry/fsimpl/proc/tasks.go index 68dac3160..4138ef19a 100644 --- a/pkg/sentry/fsimpl/proc/tasks.go +++ b/pkg/sentry/fsimpl/proc/tasks.go @@ -22,6 +22,7 @@ import ( "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" + "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" @@ -68,6 +69,14 @@ var _ kernfs.Inode = (*tasksInode)(nil) func (fs *filesystem) newTasksInode(ctx context.Context, k *kernel.Kernel, pidns *kernel.PIDNamespace, internalData *InternalData) *tasksInode { root := auth.NewRootCredentials(pidns.UserNamespace()) + // /proc is expected to have inode number + // include/linux/proc_ns.h:PROC_ROOT_INO == 1; ensure that this is the case + // by generating its inode number before any of its descendants. + rootIno := fs.NextIno() + if rootIno != 1 { + log.Traceback("proc root inode has number %d", rootIno) + } + contents := map[string]kernfs.Inode{ "cmdline": fs.newInode(ctx, root, 0444, &cmdLineData{}), "cpuinfo": fs.newInode(ctx, root, 0444, newStaticFileSetStat(cpuInfoData(k))), @@ -99,7 +108,7 @@ func (fs *filesystem) newTasksInode(ctx context.Context, k *kernel.Kernel, pidns fs: fs, fakeCgroupControllers: internalData.Cgroups, } - inode.InodeAttrs.Init(ctx, root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), linux.ModeDirectory|0555) + inode.InodeAttrs.Init(ctx, root, linux.UNNAMED_MAJOR, fs.devMinor, rootIno, linux.ModeDirectory|0555) inode.InitRefs() inode.OrderedChildren.Init(kernfs.OrderedChildrenOptions{}) diff --git a/pkg/sentry/fsimpl/tmpfs/save_restore.go b/pkg/sentry/fsimpl/tmpfs/save_restore.go index 391adc968..41d6a588d 100644 --- a/pkg/sentry/fsimpl/tmpfs/save_restore.go +++ b/pkg/sentry/fsimpl/tmpfs/save_restore.go @@ -23,6 +23,8 @@ import ( "gvisor.dev/gvisor/pkg/sentry/vfs" ) +var _ vfs.FilesystemImplSaveRestoreExtension = (*filesystem)(nil) + // saveMf is called by stateify. func (fs *filesystem) saveMf() string { if !fs.mf.IsSavable() { @@ -75,6 +77,9 @@ func (fs *filesystem) PrepareSave(ctx context.Context) error { return nil } +// BeforeResume implements vfs.FilesystemImplSaveRestoreExtension.BeforeResume. +func (fs *filesystem) BeforeResume(ctx context.Context) {} + // CompleteRestore implements // vfs.FilesystemImplSaveRestoreExtension.CompleteRestore. func (fs *filesystem) CompleteRestore(ctx context.Context, opts vfs.CompleteRestoreOptions) error { diff --git a/pkg/sentry/hostmm/hostmm.go b/pkg/sentry/hostmm/hostmm.go index b64b0aaeb..ec469aad9 100644 --- a/pkg/sentry/hostmm/hostmm.go +++ b/pkg/sentry/hostmm/hostmm.go @@ -26,23 +26,30 @@ import ( "gvisor.dev/gvisor/pkg/log" ) -// GetTransparentHugepageEnum returns the currently selected option for +// ReadTransparentHugepageEnum returns the currently selected option for // whichever of // /sys/kernel/mm/transparent_hugepage/{enabled,shmem_enabled,defrag} is // specified by filename. (Only the basename is required, not the full path.) -func GetTransparentHugepageEnum(filename string) (string, error) { +func ReadTransparentHugepageEnum(filename string) (string, error) { pathname := path.Join("/sys/kernel/mm/transparent_hugepage/", filename) data, err := os.ReadFile(pathname) if err != nil { return "", err } + return GetTransparentHugepageEnum(string(data)) +} + +// GetTransparentHugepageEnum returns the currently selected option given the +// contents of any of +// /sys/kernel/mm/transparent_hugepage/{enabled,shmem_enabled,defrag}. +func GetTransparentHugepageEnum(data string) (string, error) { // In these files, the selected option is highlighted by square brackets. - m := regexp.MustCompile(`\[.*\]`).Find(data) - if m == nil { - return "", fmt.Errorf("failed to parse %s: %q", pathname, data) + m := regexp.MustCompile(`\[.*\]`).FindString(data) + if m == "" { + return "", fmt.Errorf("failed to find selected option in %q", data) } // Remove the square brackets. - return string(m[1 : len(m)-1]), nil + return m[1 : len(m)-1], nil } // NotifyCurrentMemcgPressureCallback requests that f is called whenever the diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index d9e0a9c42..3effbc6d1 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -702,6 +702,11 @@ func (k *Kernel) SaveTo(ctx context.Context, w, pagesMetadata io.Writer, pagesFi return nil } +// BeforeResume is called before the kernel is resumed after save. +func (k *Kernel) BeforeResume(ctx context.Context) { + k.vfs.BeforeResume(ctx) +} + func (k *Kernel) saveMemoryFiles(ctx context.Context, w, pagesMetadata io.Writer, pagesFile *fd.FD, mfsToSave map[string]*pgalloc.MemoryFile, mfOpts pgalloc.SaveOpts) error { // Save the memory files' state. memoryStart := time.Now() diff --git a/pkg/sentry/state/state.go b/pkg/sentry/state/state.go index 4f82ca21d..57e884441 100644 --- a/pkg/sentry/state/state.go +++ b/pkg/sentry/state/state.go @@ -20,6 +20,7 @@ import ( "fmt" "io" + "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/fd" @@ -68,15 +69,18 @@ type SaveOpts struct { // MemoryFileSaveOpts is passed to calls to pgalloc.MemoryFile.SaveTo(). MemoryFileSaveOpts pgalloc.SaveOpts - // Callback is called prior to unpause, with any save error. - Callback func(err error) - // Resume indicates if the statefile is used for save-resume. Resume bool + + // Autosave indicates if the statefile is used for autosave. + Autosave bool } // Save saves the system state. func (opts SaveOpts) Save(ctx context.Context, k *kernel.Kernel, w *watchdog.Watchdog) error { + t, _ := CPUTime() + log.Infof("Before save CPU usage: %s", t.String()) + log.Infof("Sandbox save started, pausing all tasks.") k.Pause() k.ReceiveTaskStates() @@ -127,7 +131,22 @@ func (opts SaveOpts) Save(ctx context.Context, k *kernel.Kernel, w *watchdog.Wat } } } - opts.Callback(err) + + t1, _ := CPUTime() + log.Infof("Save CPU usage: %s", (t1 - t).String()) + if err == nil { + log.Infof("Save succeeded: exiting...") + k.SetSaveSuccess(opts.Autosave) + } else { + log.Warningf("Save failed: exiting... %v", err) + k.SetSaveError(err) + } + if opts.Resume { + k.BeforeResume(ctx) + } else { + // Kill the sandbox. + k.Kill(linux.WaitStatusExit(0)) + } return err } diff --git a/pkg/sentry/vfs/save_restore.go b/pkg/sentry/vfs/save_restore.go index 5ceb4c36d..76f4687b9 100644 --- a/pkg/sentry/vfs/save_restore.go +++ b/pkg/sentry/vfs/save_restore.go @@ -54,6 +54,10 @@ type FilesystemImplSaveRestoreExtension interface { // PrepareSave prepares this filesystem for serialization. PrepareSave(ctx context.Context) error + // BeforeResume is called before the kernel is resumed after save. It can be + // used to clean up any state that should be discarded after save. + BeforeResume(ctx context.Context) + // CompleteRestore completes restoration from checkpoint for this // filesystem after deserialization. CompleteRestore(ctx context.Context, opts CompleteRestoreOptions) error @@ -73,6 +77,17 @@ func (vfs *VirtualFilesystem) PrepareSave(ctx context.Context) error { return nil } +// BeforeResume is called before the kernel is resumed after save and allows +// filesystems to clean up S/R state. +func (vfs *VirtualFilesystem) BeforeResume(ctx context.Context) { + for fs := range vfs.getFilesystems() { + if ext, ok := fs.impl.(FilesystemImplSaveRestoreExtension); ok { + ext.BeforeResume(ctx) + } + fs.DecRef(ctx) + } +} + // CompleteRestore completes restoration from checkpoint for all filesystems // after deserialization. func (vfs *VirtualFilesystem) CompleteRestore(ctx context.Context, opts *CompleteRestoreOptions) error { diff --git a/pkg/shim/BUILD b/pkg/shim/v1/BUILD similarity index 90% rename from pkg/shim/BUILD rename to pkg/shim/v1/BUILD index f09dbbad9..3628316e6 100644 --- a/pkg/shim/BUILD +++ b/pkg/shim/v1/BUILD @@ -6,13 +6,13 @@ package( ) go_library( - name = "shim", + name = "v1", srcs = ["service.go"], visibility = ["//shim:__subpackages__"], deps = [ "//pkg/cleanup", - "//pkg/shim/extension", - "//pkg/shim/runsc", + "//pkg/shim/v1/extension", + "//pkg/shim/v1/runsc", "//pkg/sync", "@com_github_containerd_containerd//namespaces:go_default_library", "@com_github_containerd_containerd//runtime/v2/shim:go_default_library", diff --git a/pkg/shim/extension/BUILD b/pkg/shim/v1/extension/BUILD similarity index 100% rename from pkg/shim/extension/BUILD rename to pkg/shim/v1/extension/BUILD diff --git a/pkg/shim/extension/extension.go b/pkg/shim/v1/extension/extension.go similarity index 100% rename from pkg/shim/extension/extension.go rename to pkg/shim/v1/extension/extension.go diff --git a/pkg/shim/proc/BUILD b/pkg/shim/v1/proc/BUILD similarity index 92% rename from pkg/shim/proc/BUILD rename to pkg/shim/v1/proc/BUILD index c367657bc..e3bf35846 100644 --- a/pkg/shim/proc/BUILD +++ b/pkg/shim/v1/proc/BUILD @@ -25,9 +25,9 @@ go_library( deps = [ "//pkg/atomicbitops", "//pkg/cleanup", - "//pkg/shim/extension", - "//pkg/shim/runsccmd", - "//pkg/shim/utils", + "//pkg/shim/v1/extension", + "//pkg/shim/v1/runsccmd", + "//pkg/shim/v1/utils", "@com_github_containerd_console//:go_default_library", "@com_github_containerd_containerd//mount:go_default_library", "@com_github_containerd_containerd//pkg/stdio:go_default_library", diff --git a/pkg/shim/proc/deleted_state.go b/pkg/shim/v1/proc/deleted_state.go similarity index 97% rename from pkg/shim/proc/deleted_state.go rename to pkg/shim/v1/proc/deleted_state.go index 26b008dd5..cbde45148 100644 --- a/pkg/shim/proc/deleted_state.go +++ b/pkg/shim/v1/proc/deleted_state.go @@ -22,7 +22,7 @@ import ( "github.com/containerd/console" "github.com/containerd/errdefs" runc "github.com/containerd/go-runc" - "gvisor.dev/gvisor/pkg/shim/extension" + "gvisor.dev/gvisor/pkg/shim/v1/extension" ) type deletedState struct{} diff --git a/pkg/shim/proc/exec.go b/pkg/shim/v1/proc/exec.go similarity index 98% rename from pkg/shim/proc/exec.go rename to pkg/shim/v1/proc/exec.go index 6e7624415..6393cd791 100644 --- a/pkg/shim/proc/exec.go +++ b/pkg/shim/v1/proc/exec.go @@ -33,8 +33,8 @@ import ( specs "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/cleanup" - "gvisor.dev/gvisor/pkg/shim/extension" - "gvisor.dev/gvisor/pkg/shim/runsccmd" + "gvisor.dev/gvisor/pkg/shim/v1/extension" + "gvisor.dev/gvisor/pkg/shim/v1/runsccmd" ) type execProcess struct { diff --git a/pkg/shim/proc/exec_state.go b/pkg/shim/v1/proc/exec_state.go similarity index 98% rename from pkg/shim/proc/exec_state.go rename to pkg/shim/v1/proc/exec_state.go index d1c1d589f..35ac72462 100644 --- a/pkg/shim/proc/exec_state.go +++ b/pkg/shim/v1/proc/exec_state.go @@ -20,7 +20,7 @@ import ( "fmt" "github.com/containerd/console" - "gvisor.dev/gvisor/pkg/shim/extension" + "gvisor.dev/gvisor/pkg/shim/v1/extension" ) type execState interface { diff --git a/pkg/shim/proc/init.go b/pkg/shim/v1/proc/init.go similarity index 99% rename from pkg/shim/proc/init.go rename to pkg/shim/v1/proc/init.go index d6c83a41a..1868286fd 100644 --- a/pkg/shim/proc/init.go +++ b/pkg/shim/v1/proc/init.go @@ -36,9 +36,9 @@ import ( runc "github.com/containerd/go-runc" specs "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/shim/extension" - "gvisor.dev/gvisor/pkg/shim/runsccmd" - "gvisor.dev/gvisor/pkg/shim/utils" + "gvisor.dev/gvisor/pkg/shim/v1/extension" + "gvisor.dev/gvisor/pkg/shim/v1/runsccmd" + "gvisor.dev/gvisor/pkg/shim/v1/utils" ) const statusStopped = "stopped" diff --git a/pkg/shim/proc/init_state.go b/pkg/shim/v1/proc/init_state.go similarity index 99% rename from pkg/shim/proc/init_state.go rename to pkg/shim/v1/proc/init_state.go index c9894b370..d564f3a2e 100644 --- a/pkg/shim/proc/init_state.go +++ b/pkg/shim/v1/proc/init_state.go @@ -23,7 +23,7 @@ import ( runc "github.com/containerd/go-runc" "golang.org/x/sys/unix" - "gvisor.dev/gvisor/pkg/shim/extension" + "gvisor.dev/gvisor/pkg/shim/v1/extension" ) type stateTransition int diff --git a/pkg/shim/proc/io.go b/pkg/shim/v1/proc/io.go similarity index 100% rename from pkg/shim/proc/io.go rename to pkg/shim/v1/proc/io.go diff --git a/pkg/shim/proc/proc.go b/pkg/shim/v1/proc/proc.go similarity index 100% rename from pkg/shim/proc/proc.go rename to pkg/shim/v1/proc/proc.go diff --git a/pkg/shim/proc/types.go b/pkg/shim/v1/proc/types.go similarity index 100% rename from pkg/shim/proc/types.go rename to pkg/shim/v1/proc/types.go diff --git a/pkg/shim/proc/utils.go b/pkg/shim/v1/proc/utils.go similarity index 97% rename from pkg/shim/proc/utils.go rename to pkg/shim/v1/proc/utils.go index 6b8f48d43..467d667c2 100644 --- a/pkg/shim/proc/utils.go +++ b/pkg/shim/v1/proc/utils.go @@ -22,7 +22,7 @@ import ( "strings" "time" - "gvisor.dev/gvisor/pkg/shim/runsccmd" + "gvisor.dev/gvisor/pkg/shim/v1/runsccmd" ) const ( diff --git a/pkg/shim/runsc/BUILD b/pkg/shim/v1/runsc/BUILD similarity index 86% rename from pkg/shim/runsc/BUILD rename to pkg/shim/v1/runsc/BUILD index 0207fc6f3..788bb4ca1 100644 --- a/pkg/shim/runsc/BUILD +++ b/pkg/shim/v1/runsc/BUILD @@ -20,17 +20,18 @@ go_library( visibility = ["//pkg/shim:__subpackages__"], deps = [ "//pkg/cleanup", - "//pkg/shim/extension", - "//pkg/shim/proc", - "//pkg/shim/runsccmd", - "//pkg/shim/runtimeoptions", - "//pkg/shim/runtimeoptions/v14", - "//pkg/shim/utils", + "//pkg/shim/v1/extension", + "//pkg/shim/v1/proc", + "//pkg/shim/v1/runsccmd", + "//pkg/shim/v1/runtimeoptions", + "//pkg/shim/v1/runtimeoptions/v14", + "//pkg/shim/v1/utils", "//runsc/specutils", "@com_github_burntsushi_toml//:go_default_library", "@com_github_containerd_cgroups//:go_default_library", "@com_github_containerd_cgroups//stats/v1:go_default_library", "@com_github_containerd_cgroups//v2:go_default_library", + "@com_github_containerd_cgroups//v2/stats:go_default_library", "@com_github_containerd_console//:go_default_library", "@com_github_containerd_containerd//api/events:go_default_library", "@com_github_containerd_containerd//api/types/task:go_default_library", @@ -46,6 +47,7 @@ go_library( "@com_github_containerd_containerd//sys/reaper:go_default_library", "@com_github_containerd_errdefs//:go_default_library", "@com_github_containerd_fifo//:go_default_library", + "@com_github_containerd_go_runc//:go_default_library", "@com_github_containerd_log//:go_default_library", "@com_github_containerd_typeurl//:go_default_library", "@com_github_gogo_protobuf//types:go_default_library", @@ -60,7 +62,7 @@ go_test( srcs = ["service_test.go"], library = ":runsc", deps = [ - "//pkg/shim/utils", + "//pkg/shim/v1/utils", "@com_github_opencontainers_runtime_spec//specs-go:go_default_library", ], ) diff --git a/pkg/shim/runsc/api.go b/pkg/shim/v1/runsc/api.go similarity index 100% rename from pkg/shim/runsc/api.go rename to pkg/shim/v1/runsc/api.go diff --git a/pkg/shim/runsc/debug.go b/pkg/shim/v1/runsc/debug.go similarity index 100% rename from pkg/shim/runsc/debug.go rename to pkg/shim/v1/runsc/debug.go diff --git a/pkg/shim/runsc/epoll.go b/pkg/shim/v1/runsc/epoll.go similarity index 100% rename from pkg/shim/runsc/epoll.go rename to pkg/shim/v1/runsc/epoll.go diff --git a/pkg/shim/runsc/oom_v2.go b/pkg/shim/v1/runsc/oom_v2.go similarity index 100% rename from pkg/shim/runsc/oom_v2.go rename to pkg/shim/v1/runsc/oom_v2.go diff --git a/pkg/shim/runsc/options.go b/pkg/shim/v1/runsc/options.go similarity index 100% rename from pkg/shim/runsc/options.go rename to pkg/shim/v1/runsc/options.go diff --git a/pkg/shim/runsc/service.go b/pkg/shim/v1/runsc/service.go similarity index 92% rename from pkg/shim/runsc/service.go rename to pkg/shim/v1/runsc/service.go index a9c1b2653..9bb73b477 100644 --- a/pkg/shim/runsc/service.go +++ b/pkg/shim/v1/runsc/service.go @@ -29,6 +29,7 @@ import ( "github.com/containerd/cgroups" cgroupsstats "github.com/containerd/cgroups/stats/v1" cgroupsv2 "github.com/containerd/cgroups/v2" + cgroupsv2stats "github.com/containerd/cgroups/v2/stats" "github.com/containerd/console" "github.com/containerd/containerd/api/events" "github.com/containerd/containerd/api/types/task" @@ -42,6 +43,7 @@ import ( taskAPI "github.com/containerd/containerd/runtime/v2/task" "github.com/containerd/containerd/sys/reaper" "github.com/containerd/errdefs" + runc "github.com/containerd/go-runc" "github.com/containerd/log" "github.com/containerd/typeurl" "github.com/gogo/protobuf/types" @@ -49,13 +51,13 @@ import ( "github.com/sirupsen/logrus" "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/cleanup" - "gvisor.dev/gvisor/pkg/shim/runtimeoptions/v14" + "gvisor.dev/gvisor/pkg/shim/v1/runtimeoptions/v14" - "gvisor.dev/gvisor/pkg/shim/extension" - "gvisor.dev/gvisor/pkg/shim/proc" - "gvisor.dev/gvisor/pkg/shim/runsccmd" - "gvisor.dev/gvisor/pkg/shim/runtimeoptions" - "gvisor.dev/gvisor/pkg/shim/utils" + "gvisor.dev/gvisor/pkg/shim/v1/extension" + "gvisor.dev/gvisor/pkg/shim/v1/proc" + "gvisor.dev/gvisor/pkg/shim/v1/runsccmd" + "gvisor.dev/gvisor/pkg/shim/v1/runtimeoptions" + "gvisor.dev/gvisor/pkg/shim/v1/utils" "gvisor.dev/gvisor/runsc/specutils" ) @@ -660,6 +662,18 @@ func (s *runscService) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*tas // as runc. // // [0]: https://github.com/google/gvisor/blob/277a0d5a1fbe8272d4729c01ee4c6e374d047ebc/runsc/boot/events.go#L61-L81 + return s.getStats(stats, r) +} + +func (s *runscService) getStats(stats *runc.Stats, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { + if s.opts.RunscConfig["systemd-cgroup"] == "true" { + return s.getV2Stats(stats, r) + } else { + return s.getV1Stats(stats, r) + } +} + +func (s *runscService) getV1Stats(stats *runc.Stats, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { metrics := &cgroupsstats.Metrics{ CPU: &cgroupsstats.CPUStat{ Usage: &cgroupsstats.CPUUsage{ @@ -708,10 +722,45 @@ func (s *runscService) Stats(ctx context.Context, r *taskAPI.StatsRequest) (*tas } data, err := typeurl.MarshalAny(metrics) if err != nil { - log.L.Debugf("Stats error, id: %s: %v", r.ID, err) + log.L.Debugf("Stats error v1, id: %s: %v", r.ID, err) return nil, err } - log.L.Debugf("Stats success, id: %s: %+v", r.ID, data) + log.L.Debugf("Stats success v1, id: %s: %+v", r.ID, data) + return &taskAPI.StatsResponse{ + Stats: data, + }, nil +} + +func (s *runscService) getV2Stats(stats *runc.Stats, r *taskAPI.StatsRequest) (*taskAPI.StatsResponse, error) { + metrics := &cgroupsv2stats.Metrics{ + // The CGroup V2 stats are in microseconds instead of nanoseconds so divide by 1000 + CPU: &cgroupsv2stats.CPUStat{ + UsageUsec: stats.Cpu.Usage.Total / 1000, + UserUsec: stats.Cpu.Usage.User / 1000, + SystemUsec: stats.Cpu.Usage.Kernel / 1000, + NrPeriods: stats.Cpu.Throttling.Periods, + NrThrottled: stats.Cpu.Throttling.ThrottledPeriods, + ThrottledUsec: stats.Cpu.Throttling.ThrottledTime / 1000, + }, + Memory: &cgroupsv2stats.MemoryStat{ + Usage: stats.Memory.Usage.Usage, + UsageLimit: stats.Memory.Usage.Limit, + SwapUsage: stats.Memory.Swap.Usage, + SwapLimit: stats.Memory.Swap.Limit, + Slab: stats.Memory.Kernel.Usage, + File: stats.Memory.Cache, + }, + Pids: &cgroupsv2stats.PidsStat{ + Current: stats.Pids.Current, + Limit: stats.Pids.Limit, + }, + } + data, err := typeurl.MarshalAny(metrics) + if err != nil { + log.L.Debugf("Stats error v2, id: %s: %v", r.ID, err) + return nil, err + } + log.L.Debugf("Stats success v2, id: %s: %+v", r.ID, data) return &taskAPI.StatsResponse{ Stats: data, }, nil diff --git a/pkg/shim/runsc/service_linux.go b/pkg/shim/v1/runsc/service_linux.go similarity index 100% rename from pkg/shim/runsc/service_linux.go rename to pkg/shim/v1/runsc/service_linux.go diff --git a/pkg/shim/runsc/service_test.go b/pkg/shim/v1/runsc/service_test.go similarity index 98% rename from pkg/shim/runsc/service_test.go rename to pkg/shim/v1/runsc/service_test.go index 8c7464cf9..30543f37a 100644 --- a/pkg/shim/runsc/service_test.go +++ b/pkg/shim/v1/runsc/service_test.go @@ -18,7 +18,7 @@ import ( "testing" specs "github.com/opencontainers/runtime-spec/specs-go" - "gvisor.dev/gvisor/pkg/shim/utils" + "gvisor.dev/gvisor/pkg/shim/v1/utils" ) func TestCgroupPath(t *testing.T) { diff --git a/pkg/shim/runsc/state.go b/pkg/shim/v1/runsc/state.go similarity index 100% rename from pkg/shim/runsc/state.go rename to pkg/shim/v1/runsc/state.go diff --git a/pkg/shim/runsccmd/BUILD b/pkg/shim/v1/runsccmd/BUILD similarity index 100% rename from pkg/shim/runsccmd/BUILD rename to pkg/shim/v1/runsccmd/BUILD diff --git a/pkg/shim/runsccmd/runsc.go b/pkg/shim/v1/runsccmd/runsc.go similarity index 100% rename from pkg/shim/runsccmd/runsc.go rename to pkg/shim/v1/runsccmd/runsc.go diff --git a/pkg/shim/runsccmd/utils.go b/pkg/shim/v1/runsccmd/utils.go similarity index 100% rename from pkg/shim/runsccmd/utils.go rename to pkg/shim/v1/runsccmd/utils.go diff --git a/pkg/shim/runtimeoptions/BUILD b/pkg/shim/v1/runtimeoptions/BUILD similarity index 94% rename from pkg/shim/runtimeoptions/BUILD rename to pkg/shim/v1/runtimeoptions/BUILD index 54f773ae7..7db78e7e3 100644 --- a/pkg/shim/runtimeoptions/BUILD +++ b/pkg/shim/v1/runtimeoptions/BUILD @@ -18,7 +18,7 @@ go_library( "runtimeoptions.go", "runtimeoptions_cri.go", ], - visibility = ["//pkg/shim/runsc:__pkg__"], + visibility = ["//pkg/shim/v1/runsc:__pkg__"], deps = ["@com_github_gogo_protobuf//proto:go_default_library"], ) diff --git a/pkg/shim/runtimeoptions/runtimeoptions.go b/pkg/shim/v1/runtimeoptions/runtimeoptions.go similarity index 100% rename from pkg/shim/runtimeoptions/runtimeoptions.go rename to pkg/shim/v1/runtimeoptions/runtimeoptions.go diff --git a/pkg/shim/runtimeoptions/runtimeoptions.proto b/pkg/shim/v1/runtimeoptions/runtimeoptions.proto similarity index 100% rename from pkg/shim/runtimeoptions/runtimeoptions.proto rename to pkg/shim/v1/runtimeoptions/runtimeoptions.proto diff --git a/pkg/shim/runtimeoptions/runtimeoptions_cri.go b/pkg/shim/v1/runtimeoptions/runtimeoptions_cri.go similarity index 100% rename from pkg/shim/runtimeoptions/runtimeoptions_cri.go rename to pkg/shim/v1/runtimeoptions/runtimeoptions_cri.go diff --git a/pkg/shim/runtimeoptions/runtimeoptions_test.go b/pkg/shim/v1/runtimeoptions/runtimeoptions_test.go similarity index 100% rename from pkg/shim/runtimeoptions/runtimeoptions_test.go rename to pkg/shim/v1/runtimeoptions/runtimeoptions_test.go diff --git a/pkg/shim/runtimeoptions/v14/BUILD b/pkg/shim/v1/runtimeoptions/v14/BUILD similarity index 94% rename from pkg/shim/runtimeoptions/v14/BUILD rename to pkg/shim/v1/runtimeoptions/v14/BUILD index a47376a2e..027720217 100644 --- a/pkg/shim/runtimeoptions/v14/BUILD +++ b/pkg/shim/v1/runtimeoptions/v14/BUILD @@ -18,7 +18,7 @@ go_library( "runtimeoptions.go", "runtimeoptions_cri.go", ], - visibility = ["//pkg/shim/runsc:__pkg__"], + visibility = ["//pkg/shim/v1/runsc:__pkg__"], deps = ["@com_github_gogo_protobuf//proto:go_default_library"], ) diff --git a/pkg/shim/runtimeoptions/v14/runtimeoptions.go b/pkg/shim/v1/runtimeoptions/v14/runtimeoptions.go similarity index 100% rename from pkg/shim/runtimeoptions/v14/runtimeoptions.go rename to pkg/shim/v1/runtimeoptions/v14/runtimeoptions.go diff --git a/pkg/shim/runtimeoptions/v14/runtimeoptions.proto b/pkg/shim/v1/runtimeoptions/v14/runtimeoptions.proto similarity index 100% rename from pkg/shim/runtimeoptions/v14/runtimeoptions.proto rename to pkg/shim/v1/runtimeoptions/v14/runtimeoptions.proto diff --git a/pkg/shim/runtimeoptions/v14/runtimeoptions_cri.go b/pkg/shim/v1/runtimeoptions/v14/runtimeoptions_cri.go similarity index 100% rename from pkg/shim/runtimeoptions/v14/runtimeoptions_cri.go rename to pkg/shim/v1/runtimeoptions/v14/runtimeoptions_cri.go diff --git a/pkg/shim/runtimeoptions/v14/runtimeoptions_test.go b/pkg/shim/v1/runtimeoptions/v14/runtimeoptions_test.go similarity index 100% rename from pkg/shim/runtimeoptions/v14/runtimeoptions_test.go rename to pkg/shim/v1/runtimeoptions/v14/runtimeoptions_test.go diff --git a/pkg/shim/service.go b/pkg/shim/v1/service.go similarity index 98% rename from pkg/shim/service.go rename to pkg/shim/v1/service.go index 74113b738..d06140697 100644 --- a/pkg/shim/service.go +++ b/pkg/shim/v1/service.go @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package shim implements Containerd Shim v2 interface. -package shim +// Package v1 implements Containerd Shim v2 interface. +package v1 import ( "context" @@ -31,8 +31,8 @@ import ( "golang.org/x/sys/unix" "gvisor.dev/gvisor/pkg/cleanup" - "gvisor.dev/gvisor/pkg/shim/extension" - "gvisor.dev/gvisor/pkg/shim/runsc" + "gvisor.dev/gvisor/pkg/shim/v1/extension" + "gvisor.dev/gvisor/pkg/shim/v1/runsc" "gvisor.dev/gvisor/pkg/sync" ) diff --git a/pkg/shim/utils/BUILD b/pkg/shim/v1/utils/BUILD similarity index 100% rename from pkg/shim/utils/BUILD rename to pkg/shim/v1/utils/BUILD diff --git a/pkg/shim/utils/annotations.go b/pkg/shim/v1/utils/annotations.go similarity index 100% rename from pkg/shim/utils/annotations.go rename to pkg/shim/v1/utils/annotations.go diff --git a/pkg/shim/utils/utils.go b/pkg/shim/v1/utils/utils.go similarity index 100% rename from pkg/shim/utils/utils.go rename to pkg/shim/v1/utils/utils.go diff --git a/pkg/shim/utils/volumes.go b/pkg/shim/v1/utils/volumes.go similarity index 100% rename from pkg/shim/utils/volumes.go rename to pkg/shim/v1/utils/volumes.go diff --git a/pkg/shim/utils/volumes_test.go b/pkg/shim/v1/utils/volumes_test.go similarity index 100% rename from pkg/shim/utils/volumes_test.go rename to pkg/shim/v1/utils/volumes_test.go diff --git a/runsc/boot/autosave.go b/runsc/boot/autosave.go index 87cfb463d..0b787796a 100644 --- a/runsc/boot/autosave.go +++ b/runsc/boot/autosave.go @@ -18,7 +18,6 @@ import ( "bytes" "fmt" - "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/fd" "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sentry/arch" @@ -28,42 +27,19 @@ import ( "gvisor.dev/gvisor/pkg/sync" ) -func getSaveOpts(l *Loader, k *kernel.Kernel, isResume bool) state.SaveOpts { - t, _ := state.CPUTime() - log.Infof("Before save CPU usage: %s", t.String()) - saveOpts := state.SaveOpts{ - Key: nil, - Resume: isResume, - Callback: func(err error) { - t1, _ := state.CPUTime() - log.Infof("Save CPU usage: %s", (t1 - t).String()) - if err == nil { - log.Infof("Save succeeded: exiting...") - k.SetSaveSuccess(true) - } else { - log.Warningf("Save failed: exiting... %v", err) - k.SetSaveError(err) - } - - if !isResume { - // Kill the sandbox. - k.Kill(linux.WaitStatusExit(0)) - } - }, - } - return saveOpts -} - func getTargetForSaveResume(l *Loader) func(k *kernel.Kernel) { return func(k *kernel.Kernel) { l.addVersionToCheckpoint() l.addContainerSpecsToCheckpoint() - saveOpts := getSaveOpts(l, k, true /* isResume */) // Store the state file contents in a buffer for save-resume. // There is no need to verify the state file, we just need the // sandbox to continue running after save. var buf bytes.Buffer - saveOpts.Destination = &buf + saveOpts := state.SaveOpts{ + Autosave: true, + Resume: true, + Destination: &buf, + } saveOpts.Save(k.SupervisorContext(), k, l.watchdog) } } @@ -78,8 +54,11 @@ func getTargetForSaveRestore(l *Loader, files []*fd.FD) func(k *kernel.Kernel) { once.Do(func() { l.addVersionToCheckpoint() l.addContainerSpecsToCheckpoint() - saveOpts := getSaveOpts(l, k, false /* isResume */) - saveOpts.Destination = files[0] + saveOpts := state.SaveOpts{ + Autosave: true, + Resume: false, + Destination: files[0], + } if len(files) == 3 { saveOpts.PagesMetadata = files[1] saveOpts.PagesFile = files[2] diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 4ae3b787e..0dbabcd20 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -208,9 +208,7 @@ type Loader struct { // /sys/devices/virtual/dmi/id/product_name. productName string - // hostShmemHuge is the host's value of - // /sys/kernel/mm/transparent_hugepage/shmem_enabled. - hostShmemHuge string + hostTHP HostTHP // mu guards the fields below. mu sync.Mutex @@ -354,14 +352,23 @@ type Args struct { // NvidiaDriverVersion is the NVIDIA driver ABI version to use for // communicating with NVIDIA devices on the host. NvidiaDriverVersion string - // HostShmemHuge is the host's value of - // /sys/kernel/mm/transparent_hugepage/shmem_enabled, or empty if this is - // unknown. - HostShmemHuge string + // HostTHP contains host transparent hugepage settings. + HostTHP HostTHP SaveFDs []*fd.FD } +// HostTHP holds host transparent hugepage settings. +type HostTHP struct { + // ShmemEnabled is the selected option in + // /sys/kernel/mm/transparent_hugepage/shmem_enabled. + ShmemEnabled string + + // Defrag is the selected option in + // /sys/kernel/mm/transparent_hugepage/defrag. + Defrag string +} + const ( // startingStdioFD is the starting stdioFD number used during sandbox // start and restore. This makes sure the stdioFDs are always the same @@ -439,7 +446,7 @@ func New(args Args) (*Loader, error) { sharedMounts: make(map[string]*vfs.Mount), stopProfiling: stopProfiling, productName: args.ProductName, - hostShmemHuge: args.HostShmemHuge, + hostTHP: args.HostTHP, containerIDs: make(map[string]string), containerSpecs: make(map[string]*specs.Spec), saveFDs: args.SaveFDs, @@ -508,7 +515,7 @@ func New(args Args) (*Loader, error) { l.k = &kernel.Kernel{Platform: p} // Create memory file. - mf, err := createMemoryFile(args.Conf.AppHugePages, args.HostShmemHuge) + mf, err := createMemoryFile(args.Conf.AppHugePages, args.HostTHP) if err != nil { return nil, fmt.Errorf("creating memory file: %w", err) } @@ -787,7 +794,7 @@ func createPlatform(conf *config.Config, deviceFile *fd.FD) (platform.Platform, return p.New(deviceFile) } -func createMemoryFile(appHugePages bool, hostShmemHuge string) (*pgalloc.MemoryFile, error) { +func createMemoryFile(appHugePages bool, hostTHP HostTHP) (*pgalloc.MemoryFile, error) { const memfileName = "runsc-memory" memfd, err := memutil.CreateMemFD(memfileName, 0) if err != nil { @@ -801,27 +808,45 @@ func createMemoryFile(appHugePages bool, hostShmemHuge string) (*pgalloc.MemoryF // in a mount namespace in which the relevant cgroupfs is not visible. } if appHugePages { - switch hostShmemHuge { + switch hostTHP.ShmemEnabled { case "": - log.Infof("Disabling application huge pages: host shmem_huge is unknown") + log.Infof("Disabling application huge pages: host shmem_enabled is unknown") case "never", "deny": - log.Infof("Disabling application huge pages: host shmem_huge is %q", hostShmemHuge) + log.Infof("Disabling application huge pages: host shmem_enabled is %q", hostTHP.ShmemEnabled) case "advise": - log.Infof("Enabling application huge pages: host shmem_huge is %q", hostShmemHuge) - mfopts.ExpectHugepages = true - mfopts.AdviseHugepage = true + switch hostTHP.Defrag { + case "": + log.Infof("Disabling application huge pages: host shmem_enabled is %q, host defrag is unknown", hostTHP.ShmemEnabled) + case "always", "defer", "never": + // Allocations on MADV_HUGEPAGE pages will invoke direct + // compaction ("always"), wake kcompactd ("defer"), or do + // neither ("never"), consistent with host private anonymous + // memory mappings, so using MADV_HUGEPAGE shouldn't cause a + // regression vs. running natively. + log.Infof("Enabling application huge pages: host shmem_enabled is %q, host defrag is %q", hostTHP.ShmemEnabled, hostTHP.Defrag) + mfopts.ExpectHugepages = true + mfopts.AdviseHugepage = true + case "defer+madvise", "madvise": + // Allocations on MADV_HUGEPAGE pages may invoke direct + // compaction whereas allocations on host private anonymous + // memory mappings will not, so using MADV_HUGEPAGE may degrade + // performance. + log.Infof("Disabling application huge pages: host shmem_enabled is %q, host defrag is %q", hostTHP.ShmemEnabled, hostTHP.Defrag) + default: + log.Warningf("Disabling application huge pages: host shmem_enabled is %q, host defrag is unknown value %q", hostTHP.ShmemEnabled, hostTHP.Defrag) + } case "always", "within_size": - log.Infof("Enabling application huge pages: host shmem_huge is %q", hostShmemHuge) + log.Infof("Enabling application huge pages: host shmem_enabled is %q", hostTHP.ShmemEnabled) // In these cases, memfds will default to using huge pages, and we have to // explicitly ask for small pages. mfopts.ExpectHugepages = true mfopts.AdviseNoHugepage = true case "force": - log.Infof("Enabling application huge pages: host shmem_huge is %q", hostShmemHuge) + log.Infof("Enabling application huge pages: host shmem_enabled is %q", hostTHP.ShmemEnabled) // The kernel will ignore MADV_NOHUGEPAGE, so don't bother. mfopts.ExpectHugepages = true default: - log.Infof("Disabling application huge pages: host shmem_huge is unknown value %q", hostShmemHuge) + log.Warningf("Disabling application huge pages: host shmem_enabled is unknown value %q", hostTHP.ShmemEnabled) } } diff --git a/runsc/boot/restore.go b/runsc/boot/restore.go index f1e1fa0de..9ebb1603d 100644 --- a/runsc/boot/restore.go +++ b/runsc/boot/restore.go @@ -171,7 +171,7 @@ func (r *restorer) restore(l *Loader) error { Platform: p, } - mf, err := createMemoryFile(l.root.conf.AppHugePages, l.hostShmemHuge) + mf, err := createMemoryFile(l.root.conf.AppHugePages, l.hostTHP) if err != nil { return fmt.Errorf("creating memory file: %v", err) } diff --git a/runsc/cmd/boot.go b/runsc/cmd/boot.go index b18c12baa..2b78c6606 100644 --- a/runsc/cmd/boot.go +++ b/runsc/cmd/boot.go @@ -159,8 +159,7 @@ type Boot struct { // /sys/devices/virtual/dmi/id/product_name. productName string - // Value of /sys/kernel/mm/transparent_hugepage/shmem_enabled on the host. - hostShmemHuge string + hostTHP boot.HostTHP // FDs for profile data. profileFDs profile.FDArgs @@ -217,7 +216,8 @@ func (b *Boot) SetFlags(f *flag.FlagSet) { f.BoolVar(&b.attached, "attached", false, "if attached is true, kills the sandbox process when the parent process terminates") f.StringVar(&b.productName, "product-name", "", "value to show in /sys/devices/virtual/dmi/id/product_name") f.StringVar(&b.nvidiaDriverVersion, "nvidia-driver-version", "", "Nvidia driver version on the host") - f.StringVar(&b.hostShmemHuge, "host-shmem-huge", "", "value of /sys/kernel/mm/transparent_hugepage/shmem_enabled on the host") + f.StringVar(&b.hostTHP.ShmemEnabled, "host-thp-shmem-enabled", "", "value of /sys/kernel/mm/transparent_hugepage/shmem_enabled on the host") + f.StringVar(&b.hostTHP.Defrag, "host-thp-defrag", "", "value of /sys/kernel/mm/transparent_hugepage/defrag on the host") // Open FDs that are donated to the sandbox. f.IntVar(&b.specFD, "spec-fd", -1, "required fd with the container spec") @@ -275,14 +275,26 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomma argOverride["product-name"] = b.productName } } - if conf.AppHugePages && len(b.hostShmemHuge) == 0 { - hostShmemHuge, err := hostmm.GetTransparentHugepageEnum("shmem_enabled") - if err != nil { - log.Warningf("Failed to infer --host-shmem-huge: %v", err) - } else { - b.hostShmemHuge = hostShmemHuge - log.Infof("Setting host-shmem-huge: %q", b.hostShmemHuge) - argOverride["host-shmem-huge"] = b.hostShmemHuge + if conf.AppHugePages { + if len(b.hostTHP.ShmemEnabled) == 0 { + val, err := hostmm.ReadTransparentHugepageEnum("shmem_enabled") + if err != nil { + log.Warningf("Failed to infer --host-thp-shmem-enabled: %v", err) + } else { + b.hostTHP.ShmemEnabled = val + log.Infof("Setting host-thp-shmem-enabled: %q", b.hostTHP.ShmemEnabled) + argOverride["host-thp-shmem-enabled"] = b.hostTHP.ShmemEnabled + } + } + if len(b.hostTHP.Defrag) == 0 { + val, err := hostmm.ReadTransparentHugepageEnum("defrag") + if err != nil { + log.Warningf("Failed to infer --host-thp-defrag", err) + } else { + b.hostTHP.Defrag = val + log.Infof("Setting host-thp-defrag: %q", b.hostTHP.Defrag) + argOverride["host-thp-defrag"] = b.hostTHP.Defrag + } } } @@ -504,7 +516,7 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomma SinkFDs: b.sinkFDs.GetArray(), ProfileOpts: b.profileFDs.ToOpts(), NvidiaDriverVersion: b.nvidiaDriverVersion, - HostShmemHuge: b.hostShmemHuge, + HostTHP: b.hostTHP, SaveFDs: b.saveFDs.GetFDs(), } l, err := boot.New(bootArgs) diff --git a/runsc/hostsettings/BUILD b/runsc/hostsettings/BUILD index a0a4fbdd0..a98292e33 100644 --- a/runsc/hostsettings/BUILD +++ b/runsc/hostsettings/BUILD @@ -13,6 +13,7 @@ go_library( visibility = ["//:sandbox"], deps = [ "//pkg/log", + "//pkg/sentry/hostmm", "//runsc/config", ], ) diff --git a/runsc/hostsettings/hostsettings.go b/runsc/hostsettings/hostsettings.go index c2162553c..262380cc1 100644 --- a/runsc/hostsettings/hostsettings.go +++ b/runsc/hostsettings/hostsettings.go @@ -23,6 +23,7 @@ import ( "strings" "gvisor.dev/gvisor/pkg/log" + "gvisor.dev/gvisor/pkg/sentry/hostmm" "gvisor.dev/gvisor/runsc/config" ) @@ -189,12 +190,48 @@ func check(conf *config.Config) ([]*Delta, []error) { path: "/sys/kernel/mm/transparent_hugepage/shmem_enabled", purpose: "turning on transparent hugepages support in shmem increases memory allocation performance", delta: func(conf *config.Config, current string) (string, bool, error) { - // /sys/kernel/mm/transparent_hugepage/shmem_enabled is formatted like: - // `always within_size advise [never] deny force`. - if strings.Contains(current, "[always]") || strings.Contains(current, "[advise]") || strings.Contains(current, "[force]") || strings.Contains(current, "[within_size]") { + cur, err := hostmm.GetTransparentHugepageEnum(current) + if err != nil { + return "", false, err + } + switch cur { + case "always", "advise", "force", "within_size": + return "", false, nil + case "never": + return "advise", false, nil + case "deny": + // This is a non-default setting, so assume that it's + // admin-intended and don't try to change it. + return "", false, nil + default: + // Linux can reasonably add new options, so this shouldn't + // be fatal. + log.Warningf("Unknown value for /sys/kernel/mm/transparent_hugepage/shmem_enabled: %s", cur) + return "", false, nil + } + }, + }, + { + path: "/sys/kernel/mm/transparent_hugepage/defrag", + purpose: "disabling direct compaction improves page fault latency when hugepages are not immediately available", + delta: func(conf *config.Config, current string) (string, bool, error) { + cur, err := hostmm.GetTransparentHugepageEnum(current) + if err != nil { + return "", false, err + } + switch cur { + case "always", "defer", "never": + return "", false, nil + case "defer+madvise": + return "defer", false, nil + case "madvise": + return "never", false, nil + default: + // Linux can reasonably add new options, so this shouldn't + // be fatal. + log.Warningf("Unknown value for /sys/kernel/mm/transparent_hugepage/defrag: %s", cur) return "", false, nil } - return "advise", false, nil }, }, { diff --git a/shim/BUILD b/shim/BUILD index c5b30adce..67d56dfa4 100644 --- a/shim/BUILD +++ b/shim/BUILD @@ -13,7 +13,7 @@ go_binary( visibility = [ "//visibility:public", ], - deps = ["//shim/cli"], + deps = ["//shim/v1/cli"], ) pkg_tar( diff --git a/shim/main.go b/shim/main.go index b87a20d08..6e258889c 100644 --- a/shim/main.go +++ b/shim/main.go @@ -16,7 +16,7 @@ package main import ( - "gvisor.dev/gvisor/shim/cli" + "gvisor.dev/gvisor/shim/v1/cli" ) func main() { diff --git a/shim/cli/BUILD b/shim/v1/cli/BUILD similarity index 93% rename from shim/cli/BUILD rename to shim/v1/cli/BUILD index 4eb42f319..715341144 100644 --- a/shim/cli/BUILD +++ b/shim/v1/cli/BUILD @@ -13,7 +13,7 @@ go_library( "//shim:__pkg__", ], deps = [ - "//pkg/shim", + "//pkg/shim/v1", "@com_github_containerd_containerd//runtime/v2/shim:go_default_library", ], ) diff --git a/shim/cli/cli.go b/shim/v1/cli/cli.go similarity index 95% rename from shim/cli/cli.go rename to shim/v1/cli/cli.go index 068976c79..5fe24bd34 100644 --- a/shim/cli/cli.go +++ b/shim/v1/cli/cli.go @@ -19,7 +19,7 @@ package cli import ( containerdshim "github.com/containerd/containerd/runtime/v2/shim" - "gvisor.dev/gvisor/pkg/shim" + shim "gvisor.dev/gvisor/pkg/shim/v1" ) // Main is the main entrypoint. diff --git a/test/syscalls/linux/proc.cc b/test/syscalls/linux/proc.cc index f9d4e1e6f..ba32717c9 100644 --- a/test/syscalls/linux/proc.cc +++ b/test/syscalls/linux/proc.cc @@ -424,6 +424,12 @@ void RemoveUnstableCPUInfoFields(std::vector& cpu_info_fields) { } } +TEST(ProcTest, RootInodeNumber) { + struct stat s; + ASSERT_THAT(stat("/proc", &s), SyscallSucceeds()); + EXPECT_EQ(s.st_ino, 1); +} + TEST(ProcTest, NotFoundInRoot) { struct stat s; EXPECT_THAT(stat("/proc/foobar", &s), SyscallFailsWithErrno(ENOENT));