From c8c41e5e30c7b1455b56a75bcf0601c875f8f201 Mon Sep 17 00:00:00 2001 From: Fabricio Voznika Date: Wed, 30 Oct 2024 09:12:08 -0700 Subject: [PATCH] Move S/R code to separate file Move Kernel S/R code to kernel_restore.go. PiperOrigin-RevId: 691441815 --- pkg/sentry/kernel/BUILD | 1 + pkg/sentry/kernel/kernel.go | 104 ------------------------ pkg/sentry/kernel/kernel_restore.go | 119 ++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 104 deletions(-) create mode 100644 pkg/sentry/kernel/kernel_restore.go diff --git a/pkg/sentry/kernel/BUILD b/pkg/sentry/kernel/BUILD index 80ce99dc1f..2d31c94bcd 100644 --- a/pkg/sentry/kernel/BUILD +++ b/pkg/sentry/kernel/BUILD @@ -252,6 +252,7 @@ go_library( "kcov_unsafe.go", "kernel.go", "kernel_opts.go", + "kernel_restore.go", "kernel_state.go", "pending_signals.go", "pending_signals_list.go", diff --git a/pkg/sentry/kernel/kernel.go b/pkg/sentry/kernel/kernel.go index 41a3f82413..5494726293 100644 --- a/pkg/sentry/kernel/kernel.go +++ b/pkg/sentry/kernel/kernel.go @@ -393,12 +393,6 @@ type Kernel struct { UnixSocketOpts transport.UnixSocketOpts } -// Saver is an interface for saving the kernel. -type Saver interface { - SaveAsync() error - SpecEnviron(containerName string) []string -} - // InitKernelArgs holds arguments to Init. type InitKernelArgs struct { // FeatureSet is the emulated CPU feature set. @@ -1921,28 +1915,6 @@ func (k *Kernel) SetHostMount(mnt *vfs.Mount) { k.hostMount = mnt } -// AddStateToCheckpoint adds a key-value pair to be additionally checkpointed. -func (k *Kernel) AddStateToCheckpoint(key, v any) { - k.checkpointMu.Lock() - defer k.checkpointMu.Unlock() - if k.additionalCheckpointState == nil { - k.additionalCheckpointState = make(map[any]any) - } - k.additionalCheckpointState[key] = v -} - -// PopCheckpointState pops a key-value pair from the additional checkpoint -// state. If the key doesn't exist, nil is returned. -func (k *Kernel) PopCheckpointState(key any) any { - k.checkpointMu.Lock() - defer k.checkpointMu.Unlock() - if v, ok := k.additionalCheckpointState[key]; ok { - delete(k.additionalCheckpointState, key) - return v - } - return nil -} - // HostMount returns the hostfs mount. func (k *Kernel) HostMount() *vfs.Mount { return k.hostMount @@ -2202,79 +2174,3 @@ func (k *Kernel) ContainerName(cid string) string { defer k.extMu.Unlock() return k.containerNames[cid] } - -// SetSaver sets the kernel's Saver. -// Thread-compatible. -func (k *Kernel) SetSaver(s Saver) { - k.checkpointMu.Lock() - defer k.checkpointMu.Unlock() - k.saver = s -} - -// Saver returns the kernel's Saver. -// Thread-compatible. -func (k *Kernel) Saver() Saver { - k.checkpointMu.Lock() - defer k.checkpointMu.Unlock() - return k.saver -} - -// IncCheckpointCount increments the checkpoint counter. -func (k *Kernel) IncCheckpointCount() { - k.checkpointMu.Lock() - defer k.checkpointMu.Unlock() - k.checkpointCounter++ -} - -// CheckpointCount returns the current checkpoint count. Note that the result -// may be stale by the time the caller uses it. -func (k *Kernel) CheckpointCount() uint32 { - k.checkpointMu.Lock() - defer k.checkpointMu.Unlock() - return k.checkpointCounter -} - -// OnCheckpointAttempt is called when a checkpoint attempt is completed. err is -// any checkpoint errors that may have occurred. -func (k *Kernel) OnCheckpointAttempt(err error) { - k.checkpointMu.Lock() - defer k.checkpointMu.Unlock() - if err == nil { - k.checkpointCounter++ - } - k.lastCheckpointStatus = err - k.checkpointCond.Broadcast() -} - -// ResetCheckpointStatus resets the last checkpoint status, indicating a new -// checkpoint is in progress. Caller must call OnCheckpointAttempt when the -// checkpoint attempt is completed. -func (k *Kernel) ResetCheckpointStatus() { - k.checkpointMu.Lock() - defer k.checkpointMu.Unlock() - k.lastCheckpointStatus = nil -} - -// WaitCheckpoint waits for the Kernel to have been successfully checkpointed -// n-1 times, then waits for either the n-th successful checkpoint (in which -// case it returns nil) or any number of failed checkpoints (in which case it -// returns an error returned by any such failure). -func (k *Kernel) WaitCheckpoint(n uint32) error { - if n == 0 { - return nil - } - k.checkpointMu.Lock() - defer k.checkpointMu.Unlock() - if k.checkpointCounter >= n { - // n-th checkpoint already completed successfully. - return nil - } - for k.checkpointCounter < n { - if k.checkpointCounter == n-1 && k.lastCheckpointStatus != nil { - // n-th checkpoint was attempted but it had failed. - return k.lastCheckpointStatus - } - k.checkpointCond.Wait() - } - return nil -} diff --git a/pkg/sentry/kernel/kernel_restore.go b/pkg/sentry/kernel/kernel_restore.go new file mode 100644 index 0000000000..3cbb705d3f --- /dev/null +++ b/pkg/sentry/kernel/kernel_restore.go @@ -0,0 +1,119 @@ +// 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. + +package kernel + +// Saver is an interface for saving the kernel. +type Saver interface { + SaveAsync() error + SpecEnviron(containerName string) []string +} + +// AddStateToCheckpoint adds a key-value pair to be additionally checkpointed. +func (k *Kernel) AddStateToCheckpoint(key, v any) { + k.checkpointMu.Lock() + defer k.checkpointMu.Unlock() + if k.additionalCheckpointState == nil { + k.additionalCheckpointState = make(map[any]any) + } + k.additionalCheckpointState[key] = v +} + +// PopCheckpointState pops a key-value pair from the additional checkpoint +// state. If the key doesn't exist, nil is returned. +func (k *Kernel) PopCheckpointState(key any) any { + k.checkpointMu.Lock() + defer k.checkpointMu.Unlock() + if v, ok := k.additionalCheckpointState[key]; ok { + delete(k.additionalCheckpointState, key) + return v + } + return nil +} + +// SetSaver sets the kernel's Saver. +// Thread-compatible. +func (k *Kernel) SetSaver(s Saver) { + k.checkpointMu.Lock() + defer k.checkpointMu.Unlock() + k.saver = s +} + +// Saver returns the kernel's Saver. +// Thread-compatible. +func (k *Kernel) Saver() Saver { + k.checkpointMu.Lock() + defer k.checkpointMu.Unlock() + return k.saver +} + +// IncCheckpointCount increments the checkpoint counter. +func (k *Kernel) IncCheckpointCount() { + k.checkpointMu.Lock() + defer k.checkpointMu.Unlock() + k.checkpointCounter++ +} + +// CheckpointCount returns the current checkpoint count. Note that the result +// may be stale by the time the caller uses it. +func (k *Kernel) CheckpointCount() uint32 { + k.checkpointMu.Lock() + defer k.checkpointMu.Unlock() + return k.checkpointCounter +} + +// OnCheckpointAttempt is called when a checkpoint attempt is completed. err is +// any checkpoint errors that may have occurred. +func (k *Kernel) OnCheckpointAttempt(err error) { + k.checkpointMu.Lock() + defer k.checkpointMu.Unlock() + if err == nil { + k.checkpointCounter++ + } + k.lastCheckpointStatus = err + k.checkpointCond.Broadcast() +} + +// ResetCheckpointStatus resets the last checkpoint status, indicating a new +// checkpoint is in progress. Caller must call OnCheckpointAttempt when the +// checkpoint attempt is completed. +func (k *Kernel) ResetCheckpointStatus() { + k.checkpointMu.Lock() + defer k.checkpointMu.Unlock() + k.lastCheckpointStatus = nil +} + +// WaitCheckpoint waits for the Kernel to have been successfully checkpointed +// n-1 times, then waits for either the n-th successful checkpoint (in which +// case it returns nil) or any number of failed checkpoints (in which case it +// returns an error returned by any such failure). +func (k *Kernel) WaitCheckpoint(n uint32) error { + if n == 0 { + return nil + } + k.checkpointMu.Lock() + defer k.checkpointMu.Unlock() + if k.checkpointCounter >= n { + // n-th checkpoint already completed successfully. + return nil + } + for k.checkpointCounter < n { + if k.checkpointCounter == n-1 && k.lastCheckpointStatus != nil { + // n-th checkpoint was attempted but it had failed. + return k.lastCheckpointStatus + } + k.checkpointCond.Wait() + } + return nil +}