github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/vfs/save_restore.go (about)

     1  // Copyright 2020 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 vfs
    16  
    17  import (
    18  	"sync/atomic"
    19  
    20  	"github.com/nicocha30/gvisor-ligolo/pkg/context"
    21  	"github.com/nicocha30/gvisor-ligolo/pkg/refs"
    22  	"github.com/nicocha30/gvisor-ligolo/pkg/waiter"
    23  )
    24  
    25  // ErrCorruption indicates a failed restore due to external file system state in
    26  // corruption.
    27  type ErrCorruption struct {
    28  	// Err is the wrapped error.
    29  	Err error
    30  }
    31  
    32  // Error returns a sensible description of the restore error.
    33  func (e ErrCorruption) Error() string {
    34  	return "restore failed due to external file system state in corruption: " + e.Err.Error()
    35  }
    36  
    37  // FilesystemImplSaveRestoreExtension is an optional extension to
    38  // FilesystemImpl.
    39  type FilesystemImplSaveRestoreExtension interface {
    40  	// PrepareSave prepares this filesystem for serialization.
    41  	PrepareSave(ctx context.Context) error
    42  
    43  	// CompleteRestore completes restoration from checkpoint for this
    44  	// filesystem after deserialization.
    45  	CompleteRestore(ctx context.Context, opts CompleteRestoreOptions) error
    46  }
    47  
    48  // PrepareSave prepares all filesystems for serialization.
    49  func (vfs *VirtualFilesystem) PrepareSave(ctx context.Context) error {
    50  	for fs := range vfs.getFilesystems() {
    51  		if ext, ok := fs.impl.(FilesystemImplSaveRestoreExtension); ok {
    52  			if err := ext.PrepareSave(ctx); err != nil {
    53  				fs.DecRef(ctx)
    54  				return err
    55  			}
    56  		}
    57  		fs.DecRef(ctx)
    58  	}
    59  	return nil
    60  }
    61  
    62  // CompleteRestore completes restoration from checkpoint for all filesystems
    63  // after deserialization.
    64  func (vfs *VirtualFilesystem) CompleteRestore(ctx context.Context, opts *CompleteRestoreOptions) error {
    65  	for fs := range vfs.getFilesystems() {
    66  		if ext, ok := fs.impl.(FilesystemImplSaveRestoreExtension); ok {
    67  			if err := ext.CompleteRestore(ctx, *opts); err != nil {
    68  				fs.DecRef(ctx)
    69  				return err
    70  			}
    71  		}
    72  		fs.DecRef(ctx)
    73  	}
    74  	return nil
    75  }
    76  
    77  // CompleteRestoreOptions contains options to
    78  // VirtualFilesystem.CompleteRestore() and
    79  // FilesystemImplSaveRestoreExtension.CompleteRestore().
    80  type CompleteRestoreOptions struct {
    81  	// If ValidateFileSizes is true, filesystem implementations backed by
    82  	// remote filesystems should verify that file sizes have not changed
    83  	// between checkpoint and restore.
    84  	ValidateFileSizes bool
    85  
    86  	// If ValidateFileModificationTimestamps is true, filesystem
    87  	// implementations backed by remote filesystems should validate that file
    88  	// mtimes have not changed between checkpoint and restore.
    89  	ValidateFileModificationTimestamps bool
    90  }
    91  
    92  // saveMounts is called by stateify.
    93  func (vfs *VirtualFilesystem) saveMounts() []*Mount {
    94  	if atomic.LoadPointer(&vfs.mounts.slots) == nil {
    95  		// vfs.Init() was never called.
    96  		return nil
    97  	}
    98  	var mounts []*Mount
    99  	vfs.mounts.Range(func(mount *Mount) bool {
   100  		mounts = append(mounts, mount)
   101  		return true
   102  	})
   103  	return mounts
   104  }
   105  
   106  // saveKey is called by stateify.
   107  func (mnt *Mount) saveKey() VirtualDentry { return mnt.getKey() }
   108  
   109  // loadMounts is called by stateify.
   110  func (vfs *VirtualFilesystem) loadMounts(mounts []*Mount) {
   111  	if mounts == nil {
   112  		return
   113  	}
   114  	vfs.mounts.Init()
   115  	for _, mount := range mounts {
   116  		vfs.mounts.Insert(mount)
   117  	}
   118  }
   119  
   120  // loadKey is called by stateify.
   121  func (mnt *Mount) loadKey(vd VirtualDentry) { mnt.setKey(vd) }
   122  
   123  // afterLoad is called by stateify.
   124  func (mnt *Mount) afterLoad() {
   125  	if mnt.refs.Load() != 0 {
   126  		refs.Register(mnt)
   127  	}
   128  }
   129  
   130  // afterLoad is called by stateify.
   131  func (epi *epollInterest) afterLoad() {
   132  	// Mark all epollInterests as ready after restore so that the next call to
   133  	// EpollInstance.ReadEvents() rechecks their readiness.
   134  	epi.waiter.NotifyEvent(waiter.EventMaskFromLinux(epi.mask))
   135  }