From 02bd611e7ca244c504661729d0ea62dd41af2724 Mon Sep 17 00:00:00 2001 From: Fabricio Voznika Date: Wed, 24 Apr 2024 09:55:44 -0700 Subject: [PATCH] Add boot.Loader state This is to prevent an started container from restoring. It can also be extended to other checks in the future. Updates #1956 PiperOrigin-RevId: 627762283 --- runsc/boot/controller.go | 21 +++++++++++++-------- runsc/boot/loader.go | 21 ++++++++++++++++++++- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/runsc/boot/controller.go b/runsc/boot/controller.go index dc4f56d71..65ce8d1fd 100644 --- a/runsc/boot/controller.go +++ b/runsc/boot/controller.go @@ -222,6 +222,11 @@ type containerManager struct { func (cm *containerManager) StartRoot(cid *string, _ *struct{}) error { log.Debugf("containerManager.StartRoot, cid: %s", *cid) // Tell the root container to start and wait for the result. + return cm.onStart() +} + +// onStart notifies that sandbox is ready to start and wait for the result. +func (cm *containerManager) onStart() error { cm.startChan <- struct{}{} if err := <-cm.startResultChan; err != nil { return fmt.Errorf("starting sandbox: %v", err) @@ -461,6 +466,12 @@ type RestoreOpts struct { func (cm *containerManager) Restore(o *RestoreOpts, _ *struct{}) error { log.Debugf("containerManager.Restore") + if cm.l.state == restoring { + return fmt.Errorf("restore is already in progress") + } + if cm.l.state == started { + return fmt.Errorf("cannot restore a started container") + } if len(o.Files) == 0 { return fmt.Errorf("at least one file must be passed to Restore") } @@ -480,6 +491,7 @@ func (cm *containerManager) Restore(o *RestoreOpts, _ *struct{}) error { } r := restorer{container: &cm.l.root, stateFile: stateFile} + cm.l.state = restoring fileIdx := 1 if o.HavePagesFile { @@ -510,14 +522,7 @@ func (cm *containerManager) Restore(o *RestoreOpts, _ *struct{}) error { if err := r.restore(cm.l); err != nil { return err } - - // Tell the root container to start and wait for the result. - cm.startChan <- struct{}{} - if err := <-cm.startResultChan; err != nil { - return fmt.Errorf("starting sandbox: %v", err) - } - - return nil + return cm.onStart() } // Wait waits for the init process in the given container. diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 1d55ce52d..872b108df 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -151,6 +151,18 @@ type containerInfo struct { nvidiaDriverVersion string } +type loaderState int + +const ( + // created indicates that the Loader has been created, but not started yet. + created loaderState = iota + // started indicates that the Loader has been started. + started + // restoring indicates that the Loader has been created and is restoring + // containers. It will change to started after restore is completed. + restoring +) + // Loader keeps state needed to start the kernel and run the container. type Loader struct { // k is the kernel. @@ -192,6 +204,9 @@ type Loader struct { // mu guards the fields below. mu sync.Mutex + // state is guarded by mu. + state loaderState + // sharedMounts holds VFS mounts that may be shared between containers within // the same pod. It is mapped by mount source. sharedMounts map[string]*vfs.Mount @@ -847,7 +862,11 @@ func (l *Loader) run() error { log.Infof("Process should have started...") l.watchdog.Start() - return l.k.Start() + if err := l.k.Start(); err != nil { + return err + } + l.state = started + return nil } // createSubcontainer creates a new container inside the sandbox.