diff --git a/pkg/sentry/control/lifecycle.go b/pkg/sentry/control/lifecycle.go index f96b69f02b..98efe71b56 100644 --- a/pkg/sentry/control/lifecycle.go +++ b/pkg/sentry/control/lifecycle.go @@ -389,18 +389,6 @@ func (l *Lifecycle) reap(containerID string, tg *kernel.ThreadGroup) { }) } -// Pause pauses all tasks, blocking until they are stopped. -func (l *Lifecycle) Pause(_, _ *struct{}) error { - l.Kernel.Pause() - return nil -} - -// Resume resumes all tasks. -func (l *Lifecycle) Resume(_, _ *struct{}) error { - l.Kernel.Unpause() - return nil -} - // Shutdown sends signal to destroy the sentry/sandbox. func (l *Lifecycle) Shutdown(_, _ *struct{}) error { close(l.ShutdownCh) diff --git a/runsc/boot/BUILD b/runsc/boot/BUILD index a3ffe75085..b89a4dc3df 100644 --- a/runsc/boot/BUILD +++ b/runsc/boot/BUILD @@ -21,6 +21,7 @@ go_library( "mount_hints.go", "network.go", "restore.go", + "restore_impl.go", "seccheck.go", "strace.go", "vfs.go", diff --git a/runsc/boot/controller.go b/runsc/boot/controller.go index 57a0e9414b..a35b65b759 100644 --- a/runsc/boot/controller.go +++ b/runsc/boot/controller.go @@ -72,6 +72,12 @@ const ( // ContMgrRestoreSubcontainer restores a container from a statefile. ContMgrRestoreSubcontainer = "containerManager.RestoreSubcontainer" + // ContMgrPause pauses all tasks, blocking until they are stopped. + ContMgrPause = "containerManager.Pause" + + // ContMgrResume resumes all tasks. + ContMgrResume = "containerManager.Resume" + // ContMgrSignal sends a signal to a container. ContMgrSignal = "containerManager.Signal" @@ -130,12 +136,6 @@ const ( LoggingChange = "Logging.Change" ) -// Lifecycle related commands (see lifecycle.go for more details). -const ( - LifecyclePause = "Lifecycle.Pause" - LifecycleResume = "Lifecycle.Resume" -) - // Usage related commands (see usage.go for more details). const ( UsageCollect = "Usage.Collect" @@ -644,6 +644,18 @@ func (cm *containerManager) RestoreSubcontainer(args *StartArgs, _ *struct{}) er return nil } +// Pause pauses all tasks, blocking until they are stopped. +func (cm *containerManager) Pause(_, _ *struct{}) error { + cm.l.k.Pause() + return nil +} + +// Resume resumes all tasks. +func (cm *containerManager) Resume(_, _ *struct{}) error { + cm.l.k.Unpause() + return postResumeImpl(cm.l.k) +} + // Wait waits for the init process in the given container. func (cm *containerManager) Wait(cid *string, waitStatus *uint32) error { log.Debugf("containerManager.Wait, cid: %s", *cid) diff --git a/runsc/boot/restore.go b/runsc/boot/restore.go index 90daa8c3a8..f765759133 100644 --- a/runsc/boot/restore.go +++ b/runsc/boot/restore.go @@ -295,6 +295,7 @@ func (r *restorer) restore(l *Loader) error { // Release `l.mu` before calling into callbacks. cu.Clean() + // r.restoreDone() signals and waits for the sandbox to start. if err := r.restoreDone(); err != nil { return err } @@ -304,6 +305,10 @@ func (r *restorer) restore(l *Loader) error { r.pagesFile.Close() } + if err := postRestoreImpl(l.k); err != nil { + return err + } + log.Infof("Restore successful") return nil } @@ -319,10 +324,22 @@ func (l *Loader) save(o *control.SaveOpts) error { } o.Metadata["container_count"] = strconv.Itoa(l.containerCount()) + if err := preSaveImpl(l.k, o); err != nil { + return err + } + state := control.State{ Kernel: l.k, Watchdog: l.watchdog, } + if err := state.Save(o, nil); err != nil { + return err + } - return state.Save(o, nil) + if o.Resume { + if err := postResumeImpl(l.k); err != nil { + return err + } + } + return nil } diff --git a/runsc/boot/restore_impl.go b/runsc/boot/restore_impl.go new file mode 100644 index 0000000000..22244b61a1 --- /dev/null +++ b/runsc/boot/restore_impl.go @@ -0,0 +1,37 @@ +// Copyright 2024 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build !false +// +build !false + +package boot + +import ( + "gvisor.dev/gvisor/pkg/sentry/control" + "gvisor.dev/gvisor/pkg/sentry/kernel" +) + +func preSaveImpl(*kernel.Kernel, *control.SaveOpts) error { + return nil +} + +// Precondition: The kernel should be running. +func postRestoreImpl(*kernel.Kernel) error { + return nil +} + +// Precondition: The kernel should be running. +func postResumeImpl(*kernel.Kernel) error { + return nil +} diff --git a/runsc/sandbox/sandbox.go b/runsc/sandbox/sandbox.go index 6fee71d59c..3ea49d158a 100644 --- a/runsc/sandbox/sandbox.go +++ b/runsc/sandbox/sandbox.go @@ -1405,7 +1405,7 @@ func createSaveFiles(path string, direct bool, compression statefile.Compression // Pause sends the pause call for a container in the sandbox. func (s *Sandbox) Pause(cid string) error { log.Debugf("Pause sandbox %q", s.ID) - if err := s.call(boot.LifecyclePause, nil, nil); err != nil { + if err := s.call(boot.ContMgrPause, nil, nil); err != nil { return fmt.Errorf("pausing container %q: %w", cid, err) } return nil @@ -1414,7 +1414,7 @@ func (s *Sandbox) Pause(cid string) error { // Resume sends the resume call for a container in the sandbox. func (s *Sandbox) Resume(cid string) error { log.Debugf("Resume sandbox %q", s.ID) - if err := s.call(boot.LifecycleResume, nil, nil); err != nil { + if err := s.call(boot.ContMgrResume, nil, nil); err != nil { return fmt.Errorf("resuming container %q: %w", cid, err) } return nil