gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/state/state.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package state provides high-level state wrappers.
    16  package state
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  
    22  	"gvisor.dev/gvisor/pkg/context"
    23  	"gvisor.dev/gvisor/pkg/errors/linuxerr"
    24  	"gvisor.dev/gvisor/pkg/fd"
    25  	"gvisor.dev/gvisor/pkg/log"
    26  	"gvisor.dev/gvisor/pkg/sentry/inet"
    27  	"gvisor.dev/gvisor/pkg/sentry/kernel"
    28  	"gvisor.dev/gvisor/pkg/sentry/pgalloc"
    29  	"gvisor.dev/gvisor/pkg/sentry/time"
    30  	"gvisor.dev/gvisor/pkg/sentry/vfs"
    31  	"gvisor.dev/gvisor/pkg/sentry/watchdog"
    32  	"gvisor.dev/gvisor/pkg/state/statefile"
    33  )
    34  
    35  var previousMetadata map[string]string
    36  
    37  // ErrStateFile is returned when an error is encountered writing the statefile
    38  // (which may occur during open or close calls in addition to write).
    39  type ErrStateFile struct {
    40  	err error
    41  }
    42  
    43  // Error implements error.Error().
    44  func (e ErrStateFile) Error() string {
    45  	return fmt.Sprintf("statefile error: %v", e.err)
    46  }
    47  
    48  // SaveOpts contains save-related options.
    49  type SaveOpts struct {
    50  	// Destination is the save target.
    51  	Destination io.Writer
    52  
    53  	// PagesMetadata is the file into which MemoryFile metadata is stored if
    54  	// PagesMetadata is non-nil. Otherwise this content is stored in Destination.
    55  	PagesMetadata *fd.FD
    56  
    57  	// PagesFile is the file in which all MemoryFile pages are stored if
    58  	// PagesFile is non-nil. Otherwise this content is stored in Destination.
    59  	PagesFile *fd.FD
    60  
    61  	// Key is used for state integrity check.
    62  	Key []byte
    63  
    64  	// Metadata is save metadata.
    65  	Metadata map[string]string
    66  
    67  	// MemoryFileSaveOpts is passed to calls to pgalloc.MemoryFile.SaveTo().
    68  	MemoryFileSaveOpts pgalloc.SaveOpts
    69  
    70  	// Callback is called prior to unpause, with any save error.
    71  	Callback func(err error)
    72  
    73  	// Resume indicates if the statefile is used for save-resume.
    74  	Resume bool
    75  }
    76  
    77  // Save saves the system state.
    78  func (opts SaveOpts) Save(ctx context.Context, k *kernel.Kernel, w *watchdog.Watchdog) error {
    79  	log.Infof("Sandbox save started, pausing all tasks.")
    80  	k.Pause()
    81  	k.ReceiveTaskStates()
    82  	defer func() {
    83  		k.Unpause()
    84  		log.Infof("Tasks resumed after save.")
    85  	}()
    86  
    87  	w.Stop()
    88  	defer w.Start()
    89  
    90  	// Supplement the metadata.
    91  	if opts.Metadata == nil {
    92  		opts.Metadata = make(map[string]string)
    93  	}
    94  	addSaveMetadata(opts.Metadata)
    95  
    96  	// Open the statefile.
    97  	wc, err := statefile.NewWriter(opts.Destination, opts.Key, opts.Metadata)
    98  	if err != nil {
    99  		err = ErrStateFile{err}
   100  	} else {
   101  		// Save the kernel.
   102  		err = k.SaveTo(ctx, wc, opts.PagesMetadata, opts.PagesFile, opts.MemoryFileSaveOpts)
   103  
   104  		// ENOSPC is a state file error. This error can only come from
   105  		// writing the state file, and not from fs.FileOperations.Fsync
   106  		// because we wrap those in kernel.TaskSet.flushWritesToFiles.
   107  		if linuxerr.Equals(linuxerr.ENOSPC, err) {
   108  			err = ErrStateFile{err}
   109  		}
   110  
   111  		if closeErr := wc.Close(); err == nil && closeErr != nil {
   112  			err = ErrStateFile{closeErr}
   113  		}
   114  	}
   115  	opts.Callback(err)
   116  	return err
   117  }
   118  
   119  // LoadOpts contains load-related options.
   120  type LoadOpts struct {
   121  	// Source is the load source.
   122  	Source io.Reader
   123  
   124  	// PagesMetadata is the file into which MemoryFile metadata is stored if
   125  	// PagesMetadata is non-nil. Otherwise this content is stored in Source.
   126  	PagesMetadata *fd.FD
   127  
   128  	// PagesFile is the file in which all MemoryFile pages are stored if
   129  	// PagesFile is non-nil. Otherwise this content is stored in Source.
   130  	PagesFile *fd.FD
   131  
   132  	// Key is used for state integrity check.
   133  	Key []byte
   134  }
   135  
   136  // Load loads the given kernel, setting the provided platform and stack.
   137  func (opts LoadOpts) Load(ctx context.Context, k *kernel.Kernel, timeReady chan struct{}, n inet.Stack, clocks time.Clocks, vfsOpts *vfs.CompleteRestoreOptions) error {
   138  	// Open the file.
   139  	r, m, err := statefile.NewReader(opts.Source, opts.Key)
   140  	if err != nil {
   141  		return ErrStateFile{err}
   142  	}
   143  
   144  	previousMetadata = m
   145  
   146  	// Restore the Kernel object graph.
   147  	return k.LoadFrom(ctx, r, opts.PagesMetadata, opts.PagesFile, timeReady, n, clocks, vfsOpts)
   148  }